blob: cf48b7743e8f35051f3557683d3d5a47450978c3 [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
35
Eric Andersenc470f442003-07-28 09:56:35 +000036#define PROFILE 0
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000037
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000038#define JOBS ENABLE_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000039
Denis Vlasenkob012b102007-02-19 22:43:01 +000040#include <setjmp.h>
41#include <fnmatch.h>
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020042#include <sys/times.h>
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020043#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko73067272010-01-12 22:11:24 +010044
Denys Vlasenko20704f02011-03-23 17:59:27 +010045#include "busybox.h" /* for applet_names */
Denys Vlasenko20704f02011-03-23 17:59:27 +010046
Denys Vlasenko514b51d2016-10-01 14:33:08 +020047#if defined(__ANDROID_API__) && __ANDROID_API__ <= 24
48/* Bionic at least up to version 24 has no glob() */
49# undef ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenko08089c72016-10-01 14:47:52 +020050# define ENABLE_ASH_INTERNAL_GLOB 1
Denys Vlasenko514b51d2016-10-01 14:33:08 +020051#endif
52
53#if !ENABLE_ASH_INTERNAL_GLOB
54# include <glob.h>
55#endif
56
57#include "unicode.h"
Denys Vlasenko73067272010-01-12 22:11:24 +010058#include "shell_common.h"
Denys Vlasenko26777aa2010-11-22 23:49:10 +010059#if ENABLE_SH_MATH_SUPPORT
60# include "math.h"
61#endif
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020062#if ENABLE_ASH_RANDOM_SUPPORT
63# include "random.h"
Denys Vlasenko36df0482009-10-19 16:07:28 +020064#else
65# define CLEAR_RANDOM_T(rnd) ((void)0)
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020066#endif
Denis Vlasenko61befda2008-11-25 01:36:03 +000067
Denys Vlasenko1fcbff22010-06-26 02:40:08 +020068#include "NUM_APPLETS.h"
Denys Vlasenko14974842010-03-23 01:08:26 +010069#if NUM_APPLETS == 1
Denis Vlasenko61befda2008-11-25 01:36:03 +000070/* STANDALONE does not make sense, and won't compile */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020071# undef CONFIG_FEATURE_SH_STANDALONE
72# undef ENABLE_FEATURE_SH_STANDALONE
73# undef IF_FEATURE_SH_STANDALONE
Denys Vlasenko14974842010-03-23 01:08:26 +010074# undef IF_NOT_FEATURE_SH_STANDALONE
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020075# define ENABLE_FEATURE_SH_STANDALONE 0
76# define IF_FEATURE_SH_STANDALONE(...)
77# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
Eric Andersencb57d552001-06-28 07:25:16 +000078#endif
79
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000080#ifndef PIPE_BUF
Denis Vlasenko653d8e72009-03-19 21:59:35 +000081# define PIPE_BUF 4096 /* amount of buffering in a pipe */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000082#endif
83
Denys Vlasenko153fcaa2010-02-21 05:17:41 +010084#if !BB_MMU
Denis Vlasenko653d8e72009-03-19 21:59:35 +000085# error "Do not even bother, ash will not run on NOMMU machine"
Denis Vlasenkob012b102007-02-19 22:43:01 +000086#endif
87
Denys Vlasenko771f1992010-07-16 14:31:34 +020088//config:config ASH
89//config: bool "ash"
90//config: default y
91//config: depends on !NOMMU
92//config: help
93//config: Tha 'ash' shell adds about 60k in the default configuration and is
94//config: the most complete and most pedantically correct shell included with
95//config: busybox. This shell is actually a derivative of the Debian 'dash'
96//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
97//config: (written by Kenneth Almquist) from NetBSD.
98//config:
Denys Vlasenko514b51d2016-10-01 14:33:08 +020099//config:config ASH_OPTIMIZE_FOR_SIZE
100//config: bool "Optimize for size instead of speed"
101//config: default y
102//config: depends on ASH
103//config: help
104//config: Compile ash for reduced size at the price of speed.
105//config:
106//config:config ASH_INTERNAL_GLOB
107//config: bool "Use internal glob() implementation"
108//config: default n
109//config: depends on ASH
110//config: help
111//config: Do not use glob() function from libc, use internal implementation.
112//config: Use this if you are getting "glob.h: No such file or directory"
113//config: or similar build errors.
114//config:
115//config:config ASH_RANDOM_SUPPORT
116//config: bool "Pseudorandom generator and $RANDOM variable"
117//config: default y
118//config: depends on ASH
119//config: help
120//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
121//config: Each read of "$RANDOM" will generate a new pseudorandom value.
122//config: You can reset the generator by using a specified start value.
123//config: After "unset RANDOM" the generator will switch off and this
124//config: variable will no longer have special treatment.
125//config:
126//config:config ASH_EXPAND_PRMT
127//config: bool "Expand prompt string"
128//config: default y
129//config: depends on ASH
130//config: help
131//config: "PS#" may contain volatile content, such as backquote commands.
132//config: This option recreates the prompt string from the environment
133//config: variable each time it is displayed.
134//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200135//config:config ASH_BASH_COMPAT
136//config: bool "bash-compatible extensions"
137//config: default y
138//config: depends on ASH
139//config: help
140//config: Enable bash-compatible extensions.
141//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +0100142//config:config ASH_IDLE_TIMEOUT
143//config: bool "Idle timeout variable"
144//config: default n
145//config: depends on ASH
146//config: help
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100147//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko046341e2011-02-04 17:53:59 +0100148//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200149//config:config ASH_JOB_CONTROL
150//config: bool "Job control"
151//config: default y
152//config: depends on ASH
153//config: help
154//config: Enable job control in the ash shell.
155//config:
156//config:config ASH_ALIAS
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100157//config: bool "Alias support"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200158//config: default y
159//config: depends on ASH
160//config: help
161//config: Enable alias support in the ash shell.
162//config:
163//config:config ASH_GETOPTS
164//config: bool "Builtin getopt to parse positional parameters"
165//config: default y
166//config: depends on ASH
167//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100168//config: Enable support for getopts builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200169//config:
170//config:config ASH_BUILTIN_ECHO
171//config: bool "Builtin version of 'echo'"
172//config: default y
173//config: depends on ASH
174//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100175//config: Enable support for echo builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200176//config:
177//config:config ASH_BUILTIN_PRINTF
178//config: bool "Builtin version of 'printf'"
179//config: default y
180//config: depends on ASH
181//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100182//config: Enable support for printf builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200183//config:
184//config:config ASH_BUILTIN_TEST
185//config: bool "Builtin version of 'test'"
186//config: default y
187//config: depends on ASH
188//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100189//config: Enable support for test builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200190//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200191//config:config ASH_HELP
192//config: bool "help builtin"
193//config: default y
194//config: depends on ASH
195//config: help
196//config: Enable help builtin in ash.
197//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200198//config:config ASH_CMDCMD
199//config: bool "'command' command to override shell builtins"
200//config: default y
201//config: depends on ASH
202//config: help
203//config: Enable support for the ash 'command' builtin, which allows
204//config: you to run the specified command with the specified arguments,
205//config: even when there is an ash builtin command with the same name.
206//config:
207//config:config ASH_MAIL
208//config: bool "Check for new mail on interactive shells"
209//config: default n
210//config: depends on ASH
211//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100212//config: Enable "check for new mail" function in the ash shell.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200213//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200214
Denys Vlasenko20704f02011-03-23 17:59:27 +0100215//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
216//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
217//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
218
219//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
220//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
221
Denis Vlasenkob012b102007-02-19 22:43:01 +0000222
Denis Vlasenko01631112007-12-16 17:20:38 +0000223/* ============ Hash table sizes. Configurable. */
224
225#define VTABSIZE 39
226#define ATABSIZE 39
227#define CMDTABLESIZE 31 /* should be prime */
228
229
Denis Vlasenkob012b102007-02-19 22:43:01 +0000230/* ============ Shell options */
231
232static const char *const optletters_optnames[] = {
233 "e" "errexit",
234 "f" "noglob",
235 "I" "ignoreeof",
236 "i" "interactive",
237 "m" "monitor",
238 "n" "noexec",
239 "s" "stdin",
240 "x" "xtrace",
241 "v" "verbose",
242 "C" "noclobber",
243 "a" "allexport",
244 "b" "notify",
245 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100246 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100247#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100248 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100249#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000250#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000251 ,"\0" "nolog"
252 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000253#endif
254};
255
Denys Vlasenko285ad152009-12-04 23:02:27 +0100256#define optletters(n) optletters_optnames[n][0]
257#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000258
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000259enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000260
Eric Andersenc470f442003-07-28 09:56:35 +0000261
Denis Vlasenkob012b102007-02-19 22:43:01 +0000262/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000263
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200264#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000265
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000266/*
Eric Andersenc470f442003-07-28 09:56:35 +0000267 * We enclose jmp_buf in a structure so that we can declare pointers to
268 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000269 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000270 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000271 * exception handlers, the user should save the value of handler on entry
272 * to an inner scope, set handler to point to a jmploc structure for the
273 * inner scope, and restore handler on exit from the scope.
274 */
Eric Andersenc470f442003-07-28 09:56:35 +0000275struct jmploc {
276 jmp_buf loc;
277};
Denis Vlasenko01631112007-12-16 17:20:38 +0000278
279struct globals_misc {
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200280 uint8_t exitstatus; /* exit status of last command */
281 uint8_t back_exitstatus;/* exit status of backquoted command */
282 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
283 int rootpid; /* pid of main shell */
Denis Vlasenko01631112007-12-16 17:20:38 +0000284 /* shell level: 0 for the main shell, 1 for its children, and so on */
285 int shlvl;
286#define rootshell (!shlvl)
287 char *minusc; /* argument to -c option */
288
289 char *curdir; // = nullstr; /* current working directory */
290 char *physdir; // = nullstr; /* physical working directory */
291
292 char *arg0; /* value of $0 */
293
294 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000295
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200296 volatile int suppress_int; /* counter */
297 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000298 /* last pending signal */
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200299 volatile /*sig_atomic_t*/ smallint pending_sig;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000300 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000301 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000302#define EXINT 0 /* SIGINT received */
303#define EXERROR 1 /* a generic error */
Eric Andersenc470f442003-07-28 09:56:35 +0000304#define EXEXIT 4 /* exit the shell */
305#define EXSIG 5 /* trapped signal in wait(1) */
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 )
374#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000375#define isloginsh (G_misc.isloginsh )
376#define nullstr (G_misc.nullstr )
377#define optlist (G_misc.optlist )
378#define sigmode (G_misc.sigmode )
379#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200380#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000381#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200382#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200383#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000384#define backgndpid (G_misc.backgndpid )
Denis Vlasenko01631112007-12-16 17:20:38 +0000385#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000386 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
387 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000388 curdir = nullstr; \
389 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200390 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000391} while (0)
392
393
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000394/* ============ DEBUG */
395#if DEBUG
396static void trace_printf(const char *fmt, ...);
397static void trace_vprintf(const char *fmt, va_list va);
398# define TRACE(param) trace_printf param
399# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000400# define close(fd) do { \
401 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000402 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200403 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000404 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000405} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000406#else
407# define TRACE(param)
408# define TRACEV(param)
409#endif
410
411
Denis Vlasenko559691a2008-10-05 18:39:31 +0000412/* ============ Utility functions */
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100413#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
414#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
415
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200416static int
417isdigit_str9(const char *str)
Denis Vlasenko559691a2008-10-05 18:39:31 +0000418{
419 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
420 while (--maxlen && isdigit(*str))
421 str++;
422 return (*str == '\0');
423}
Denis Vlasenko01631112007-12-16 17:20:38 +0000424
Denys Vlasenko37dc08b2016-10-02 04:38:07 +0200425static const char *
426var_end(const char *var)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200427{
428 while (*var)
429 if (*var++ == '=')
430 break;
431 return var;
432}
433
Denis Vlasenko559691a2008-10-05 18:39:31 +0000434
435/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100436
437static void exitshell(void) NORETURN;
438
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000439/*
Eric Andersen2870d962001-07-02 17:27:21 +0000440 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000441 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000442 * much more efficient and portable. (But hacking the kernel is so much
443 * more fun than worrying about efficiency and portability. :-))
444 */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000445#define INT_OFF do { \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200446 suppress_int++; \
Denys Vlasenkode892052016-10-02 01:49:13 +0200447 barrier(); \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000448} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000449
450/*
451 * Called to raise an exception. Since C doesn't include exceptions, we
452 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000453 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000454 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000455static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000456static void
457raise_exception(int e)
458{
459#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000460 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000461 abort();
462#endif
463 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000464 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000465 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000466}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000467#if DEBUG
468#define raise_exception(e) do { \
469 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
470 raise_exception(e); \
471} while (0)
472#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000473
474/*
Denys Vlasenkof37e1152016-10-07 03:17:28 +0200475 * Called when a SIGINT is received. (If the user specifies
Denis Vlasenkob012b102007-02-19 22:43:01 +0000476 * that SIGINT is to be trapped or ignored using the trap builtin, then
477 * this routine is not called.) Suppressint is nonzero when interrupts
478 * are held using the INT_OFF macro. (The test for iflag is just
479 * defensive programming.)
480 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000481static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000482static void
483raise_interrupt(void)
484{
Denis Vlasenko4b875702009-03-19 13:30:04 +0000485 int ex_type;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000486
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200487 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000488 /* Signal is not automatically unmasked after it is raised,
489 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000490 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200491 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000492
Denis Vlasenko4b875702009-03-19 13:30:04 +0000493 ex_type = EXSIG;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000494 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
495 if (!(rootshell && iflag)) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000496 /* Kill ourself with SIGINT */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000497 signal(SIGINT, SIG_DFL);
498 raise(SIGINT);
499 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000500 ex_type = EXINT;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000501 }
Denys Vlasenko4d12e942016-10-01 16:03:11 +0200502 /* bash: ^C even on empty command line sets $? */
503 exitstatus = SIGINT + 128;
Denis Vlasenko4b875702009-03-19 13:30:04 +0000504 raise_exception(ex_type);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000505 /* NOTREACHED */
506}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000507#if DEBUG
508#define raise_interrupt() do { \
509 TRACE(("raising interrupt on line %d\n", __LINE__)); \
510 raise_interrupt(); \
511} while (0)
512#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000513
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000514static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000515int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000516{
Denys Vlasenkode892052016-10-02 01:49:13 +0200517 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200518 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000519 raise_interrupt();
520 }
521}
522#define INT_ON int_on()
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000523static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000524force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000525{
Denys Vlasenkode892052016-10-02 01:49:13 +0200526 barrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200527 suppress_int = 0;
528 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000529 raise_interrupt();
530}
531#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000532
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200533#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000534
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000535#define RESTORE_INT(v) do { \
Denys Vlasenkode892052016-10-02 01:49:13 +0200536 barrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200537 suppress_int = (v); \
538 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000539 raise_interrupt(); \
540} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000541
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000542
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000543/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000544
Eric Andersenc470f442003-07-28 09:56:35 +0000545static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000546outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000547{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000548 INT_OFF;
549 fputs(p, file);
550 INT_ON;
551}
552
553static void
554flush_stdout_stderr(void)
555{
556 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100557 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000558 INT_ON;
559}
560
Denys Vlasenko9c541002015-10-07 15:44:36 +0200561/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000562static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200563newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000564{
565 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200566 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000567 fflush(dest);
568 INT_ON;
569}
570
571static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
572static int
573out1fmt(const char *fmt, ...)
574{
575 va_list ap;
576 int r;
577
578 INT_OFF;
579 va_start(ap, fmt);
580 r = vprintf(fmt, ap);
581 va_end(ap);
582 INT_ON;
583 return r;
584}
585
586static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
587static int
588fmtstr(char *outbuf, size_t length, const char *fmt, ...)
589{
590 va_list ap;
591 int ret;
592
593 va_start(ap, fmt);
594 INT_OFF;
595 ret = vsnprintf(outbuf, length, fmt, ap);
596 va_end(ap);
597 INT_ON;
598 return ret;
599}
600
601static void
602out1str(const char *p)
603{
604 outstr(p, stdout);
605}
606
607static void
608out2str(const char *p)
609{
610 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100611 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000612}
613
614
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000615/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000616
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000617/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100618#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200619#define CTLESC ((unsigned char)'\201') /* escape next character */
620#define CTLVAR ((unsigned char)'\202') /* variable defn */
621#define CTLENDVAR ((unsigned char)'\203')
622#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200623#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
624#define CTLENDARI ((unsigned char)'\207')
625#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100626#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000627
628/* variable substitution byte (follows CTLVAR) */
629#define VSTYPE 0x0f /* type of variable substitution */
630#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000631
632/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000633#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
634#define VSMINUS 0x2 /* ${var-text} */
635#define VSPLUS 0x3 /* ${var+text} */
636#define VSQUESTION 0x4 /* ${var?message} */
637#define VSASSIGN 0x5 /* ${var=text} */
638#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
639#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
640#define VSTRIMLEFT 0x8 /* ${var#pattern} */
641#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
642#define VSLENGTH 0xa /* ${#var} */
643#if ENABLE_ASH_BASH_COMPAT
644#define VSSUBSTR 0xc /* ${var:position:length} */
645#define VSREPLACE 0xd /* ${var/pattern/replacement} */
646#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
647#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000648
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000649static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200650 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000651};
Ron Yorston549deab2015-05-18 09:57:51 +0200652#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000653
Denis Vlasenko559691a2008-10-05 18:39:31 +0000654#define NCMD 0
655#define NPIPE 1
656#define NREDIR 2
657#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000658#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000659#define NAND 5
660#define NOR 6
661#define NSEMI 7
662#define NIF 8
663#define NWHILE 9
664#define NUNTIL 10
665#define NFOR 11
666#define NCASE 12
667#define NCLIST 13
668#define NDEFUN 14
669#define NARG 15
670#define NTO 16
671#if ENABLE_ASH_BASH_COMPAT
672#define NTO2 17
673#endif
674#define NCLOBBER 18
675#define NFROM 19
676#define NFROMTO 20
677#define NAPPEND 21
678#define NTOFD 22
679#define NFROMFD 23
680#define NHERE 24
681#define NXHERE 25
682#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000683#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000684
685union node;
686
687struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000688 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000689 union node *assign;
690 union node *args;
691 union node *redirect;
692};
693
694struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000695 smallint type;
696 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000697 struct nodelist *cmdlist;
698};
699
700struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000701 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000702 union node *n;
703 union node *redirect;
704};
705
706struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000707 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000708 union node *ch1;
709 union node *ch2;
710};
711
712struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000713 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000714 union node *test;
715 union node *ifpart;
716 union node *elsepart;
717};
718
719struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000720 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000721 union node *args;
722 union node *body;
723 char *var;
724};
725
726struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000727 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000728 union node *expr;
729 union node *cases;
730};
731
732struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000733 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000734 union node *next;
735 union node *pattern;
736 union node *body;
737};
738
739struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000740 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000741 union node *next;
742 char *text;
743 struct nodelist *backquote;
744};
745
Denis Vlasenko559691a2008-10-05 18:39:31 +0000746/* nfile and ndup layout must match!
747 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
748 * that it is actually NTO2 (>&file), and change its type.
749 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000750struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000751 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000752 union node *next;
753 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000754 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000755 union node *fname;
756 char *expfname;
757};
758
759struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000760 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000761 union node *next;
762 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000763 int dupfd;
764 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000765 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000766};
767
768struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000769 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000770 union node *next;
771 int fd;
772 union node *doc;
773};
774
775struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000776 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000777 union node *com;
778};
779
780union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000781 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000782 struct ncmd ncmd;
783 struct npipe npipe;
784 struct nredir nredir;
785 struct nbinary nbinary;
786 struct nif nif;
787 struct nfor nfor;
788 struct ncase ncase;
789 struct nclist nclist;
790 struct narg narg;
791 struct nfile nfile;
792 struct ndup ndup;
793 struct nhere nhere;
794 struct nnot nnot;
795};
796
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200797/*
798 * NODE_EOF is returned by parsecmd when it encounters an end of file.
799 * It must be distinct from NULL.
800 */
801#define NODE_EOF ((union node *) -1L)
802
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000803struct nodelist {
804 struct nodelist *next;
805 union node *n;
806};
807
808struct funcnode {
809 int count;
810 union node n;
811};
812
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000813/*
814 * Free a parse tree.
815 */
816static void
817freefunc(struct funcnode *f)
818{
819 if (f && --f->count < 0)
820 free(f);
821}
822
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000823
824/* ============ Debugging output */
825
826#if DEBUG
827
828static FILE *tracefile;
829
830static void
831trace_printf(const char *fmt, ...)
832{
833 va_list va;
834
835 if (debug != 1)
836 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000837 if (DEBUG_TIME)
838 fprintf(tracefile, "%u ", (int) time(NULL));
839 if (DEBUG_PID)
840 fprintf(tracefile, "[%u] ", (int) getpid());
841 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200842 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000843 va_start(va, fmt);
844 vfprintf(tracefile, fmt, va);
845 va_end(va);
846}
847
848static void
849trace_vprintf(const char *fmt, va_list va)
850{
851 if (debug != 1)
852 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000853 if (DEBUG_TIME)
854 fprintf(tracefile, "%u ", (int) time(NULL));
855 if (DEBUG_PID)
856 fprintf(tracefile, "[%u] ", (int) getpid());
857 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200858 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000859 vfprintf(tracefile, fmt, va);
860}
861
862static void
863trace_puts(const char *s)
864{
865 if (debug != 1)
866 return;
867 fputs(s, tracefile);
868}
869
870static void
871trace_puts_quoted(char *s)
872{
873 char *p;
874 char c;
875
876 if (debug != 1)
877 return;
878 putc('"', tracefile);
879 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100880 switch ((unsigned char)*p) {
881 case '\n': c = 'n'; goto backslash;
882 case '\t': c = 't'; goto backslash;
883 case '\r': c = 'r'; goto backslash;
884 case '\"': c = '\"'; goto backslash;
885 case '\\': c = '\\'; goto backslash;
886 case CTLESC: c = 'e'; goto backslash;
887 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100888 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000889 backslash:
890 putc('\\', tracefile);
891 putc(c, tracefile);
892 break;
893 default:
894 if (*p >= ' ' && *p <= '~')
895 putc(*p, tracefile);
896 else {
897 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100898 putc((*p >> 6) & 03, tracefile);
899 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000900 putc(*p & 07, tracefile);
901 }
902 break;
903 }
904 }
905 putc('"', tracefile);
906}
907
908static void
909trace_puts_args(char **ap)
910{
911 if (debug != 1)
912 return;
913 if (!*ap)
914 return;
915 while (1) {
916 trace_puts_quoted(*ap);
917 if (!*++ap) {
918 putc('\n', tracefile);
919 break;
920 }
921 putc(' ', tracefile);
922 }
923}
924
925static void
926opentrace(void)
927{
928 char s[100];
929#ifdef O_APPEND
930 int flags;
931#endif
932
933 if (debug != 1) {
934 if (tracefile)
935 fflush(tracefile);
936 /* leave open because libedit might be using it */
937 return;
938 }
939 strcpy(s, "./trace");
940 if (tracefile) {
941 if (!freopen(s, "a", tracefile)) {
942 fprintf(stderr, "Can't re-open %s\n", s);
943 debug = 0;
944 return;
945 }
946 } else {
947 tracefile = fopen(s, "a");
948 if (tracefile == NULL) {
949 fprintf(stderr, "Can't open %s\n", s);
950 debug = 0;
951 return;
952 }
953 }
954#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000955 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000956 if (flags >= 0)
957 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
958#endif
959 setlinebuf(tracefile);
960 fputs("\nTracing started.\n", tracefile);
961}
962
963static void
964indent(int amount, char *pfx, FILE *fp)
965{
966 int i;
967
968 for (i = 0; i < amount; i++) {
969 if (pfx && i == amount - 1)
970 fputs(pfx, fp);
971 putc('\t', fp);
972 }
973}
974
975/* little circular references here... */
976static void shtree(union node *n, int ind, char *pfx, FILE *fp);
977
978static void
979sharg(union node *arg, FILE *fp)
980{
981 char *p;
982 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100983 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000984
985 if (arg->type != NARG) {
986 out1fmt("<node type %d>\n", arg->type);
987 abort();
988 }
989 bqlist = arg->narg.backquote;
990 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100991 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000992 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700993 p++;
994 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000995 break;
996 case CTLVAR:
997 putc('$', fp);
998 putc('{', fp);
999 subtype = *++p;
1000 if (subtype == VSLENGTH)
1001 putc('#', fp);
1002
Dan Fandrich77d48722010-09-07 23:38:28 -07001003 while (*p != '=') {
1004 putc(*p, fp);
1005 p++;
1006 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001007
1008 if (subtype & VSNUL)
1009 putc(':', fp);
1010
1011 switch (subtype & VSTYPE) {
1012 case VSNORMAL:
1013 putc('}', fp);
1014 break;
1015 case VSMINUS:
1016 putc('-', fp);
1017 break;
1018 case VSPLUS:
1019 putc('+', fp);
1020 break;
1021 case VSQUESTION:
1022 putc('?', fp);
1023 break;
1024 case VSASSIGN:
1025 putc('=', fp);
1026 break;
1027 case VSTRIMLEFT:
1028 putc('#', fp);
1029 break;
1030 case VSTRIMLEFTMAX:
1031 putc('#', fp);
1032 putc('#', fp);
1033 break;
1034 case VSTRIMRIGHT:
1035 putc('%', fp);
1036 break;
1037 case VSTRIMRIGHTMAX:
1038 putc('%', fp);
1039 putc('%', fp);
1040 break;
1041 case VSLENGTH:
1042 break;
1043 default:
1044 out1fmt("<subtype %d>", subtype);
1045 }
1046 break;
1047 case CTLENDVAR:
1048 putc('}', fp);
1049 break;
1050 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001051 putc('$', fp);
1052 putc('(', fp);
1053 shtree(bqlist->n, -1, NULL, fp);
1054 putc(')', fp);
1055 break;
1056 default:
1057 putc(*p, fp);
1058 break;
1059 }
1060 }
1061}
1062
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001063static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001064shcmd(union node *cmd, FILE *fp)
1065{
1066 union node *np;
1067 int first;
1068 const char *s;
1069 int dftfd;
1070
1071 first = 1;
1072 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001073 if (!first)
1074 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001075 sharg(np, fp);
1076 first = 0;
1077 }
1078 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001079 if (!first)
1080 putc(' ', fp);
1081 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001082 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001083 case NTO: s = ">>"+1; dftfd = 1; break;
1084 case NCLOBBER: s = ">|"; dftfd = 1; break;
1085 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001086#if ENABLE_ASH_BASH_COMPAT
1087 case NTO2:
1088#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001089 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001090 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001091 case NFROMFD: s = "<&"; break;
1092 case NFROMTO: s = "<>"; break;
1093 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001094 }
1095 if (np->nfile.fd != dftfd)
1096 fprintf(fp, "%d", np->nfile.fd);
1097 fputs(s, fp);
1098 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1099 fprintf(fp, "%d", np->ndup.dupfd);
1100 } else {
1101 sharg(np->nfile.fname, fp);
1102 }
1103 first = 0;
1104 }
1105}
1106
1107static void
1108shtree(union node *n, int ind, char *pfx, FILE *fp)
1109{
1110 struct nodelist *lp;
1111 const char *s;
1112
1113 if (n == NULL)
1114 return;
1115
1116 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001117
1118 if (n == NODE_EOF) {
1119 fputs("<EOF>", fp);
1120 return;
1121 }
1122
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001123 switch (n->type) {
1124 case NSEMI:
1125 s = "; ";
1126 goto binop;
1127 case NAND:
1128 s = " && ";
1129 goto binop;
1130 case NOR:
1131 s = " || ";
1132 binop:
1133 shtree(n->nbinary.ch1, ind, NULL, fp);
1134 /* if (ind < 0) */
1135 fputs(s, fp);
1136 shtree(n->nbinary.ch2, ind, NULL, fp);
1137 break;
1138 case NCMD:
1139 shcmd(n, fp);
1140 if (ind >= 0)
1141 putc('\n', fp);
1142 break;
1143 case NPIPE:
1144 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001145 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001146 if (lp->next)
1147 fputs(" | ", fp);
1148 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001149 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001150 fputs(" &", fp);
1151 if (ind >= 0)
1152 putc('\n', fp);
1153 break;
1154 default:
1155 fprintf(fp, "<node type %d>", n->type);
1156 if (ind >= 0)
1157 putc('\n', fp);
1158 break;
1159 }
1160}
1161
1162static void
1163showtree(union node *n)
1164{
1165 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001166 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001167}
1168
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001169#endif /* DEBUG */
1170
1171
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001172/* ============ Parser data */
1173
1174/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001175 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1176 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001177struct strlist {
1178 struct strlist *next;
1179 char *text;
1180};
1181
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001182struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001183
Denis Vlasenkob012b102007-02-19 22:43:01 +00001184struct strpush {
1185 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001186 char *prev_string;
1187 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001188#if ENABLE_ASH_ALIAS
1189 struct alias *ap; /* if push was associated with an alias */
1190#endif
1191 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001192
1193 /* Remember last two characters for pungetc. */
1194 int lastc[2];
1195
1196 /* Number of outstanding calls to pungetc. */
1197 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001198};
1199
1200struct parsefile {
1201 struct parsefile *prev; /* preceding file on stack */
1202 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001203 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001204 int left_in_line; /* number of chars left in this line */
1205 int left_in_buffer; /* number of chars left in this buffer past the line */
1206 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001207 char *buf; /* input buffer */
1208 struct strpush *strpush; /* for pushing strings at this level */
1209 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001210
1211 /* Remember last two characters for pungetc. */
1212 int lastc[2];
1213
1214 /* Number of outstanding calls to pungetc. */
1215 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001216};
1217
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001218static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001219static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001220static int startlinno; /* line # where last token started */
1221static char *commandname; /* currently executing command */
1222static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001223
1224
1225/* ============ Message printing */
1226
1227static void
1228ash_vmsg(const char *msg, va_list ap)
1229{
1230 fprintf(stderr, "%s: ", arg0);
1231 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001232 if (strcmp(arg0, commandname))
1233 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001234 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001235 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001236 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001237 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001238 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001239}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001240
1241/*
1242 * Exverror is called to raise the error exception. If the second argument
1243 * is not NULL then error prints an error message using printf style
1244 * formatting. It then raises the error exception.
1245 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001246static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001247static void
1248ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001249{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001250#if DEBUG
1251 if (msg) {
1252 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1253 TRACEV((msg, ap));
1254 TRACE(("\") pid=%d\n", getpid()));
1255 } else
1256 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1257 if (msg)
1258#endif
1259 ash_vmsg(msg, ap);
1260
1261 flush_stdout_stderr();
1262 raise_exception(cond);
1263 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001264}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001265
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001266static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001267static void
1268ash_msg_and_raise_error(const char *msg, ...)
1269{
1270 va_list ap;
1271
1272 va_start(ap, msg);
1273 ash_vmsg_and_raise(EXERROR, msg, ap);
1274 /* NOTREACHED */
1275 va_end(ap);
1276}
1277
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001278static void raise_error_syntax(const char *) NORETURN;
1279static void
1280raise_error_syntax(const char *msg)
1281{
1282 ash_msg_and_raise_error("syntax error: %s", msg);
1283 /* NOTREACHED */
1284}
1285
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001286static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001287static void
1288ash_msg_and_raise(int cond, const char *msg, ...)
1289{
1290 va_list ap;
1291
1292 va_start(ap, msg);
1293 ash_vmsg_and_raise(cond, msg, ap);
1294 /* NOTREACHED */
1295 va_end(ap);
1296}
1297
1298/*
1299 * error/warning routines for external builtins
1300 */
1301static void
1302ash_msg(const char *fmt, ...)
1303{
1304 va_list ap;
1305
1306 va_start(ap, fmt);
1307 ash_vmsg(fmt, ap);
1308 va_end(ap);
1309}
1310
1311/*
1312 * Return a string describing an error. The returned string may be a
1313 * pointer to a static buffer that will be overwritten on the next call.
1314 * Action describes the operation that got the error.
1315 */
1316static const char *
1317errmsg(int e, const char *em)
1318{
1319 if (e == ENOENT || e == ENOTDIR) {
1320 return em;
1321 }
1322 return strerror(e);
1323}
1324
1325
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001326/* ============ Memory allocation */
1327
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001328#if 0
1329/* I consider these wrappers nearly useless:
1330 * ok, they return you to nearest exception handler, but
1331 * how much memory do you leak in the process, making
1332 * memory starvation worse?
1333 */
1334static void *
1335ckrealloc(void * p, size_t nbytes)
1336{
1337 p = realloc(p, nbytes);
1338 if (!p)
1339 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1340 return p;
1341}
1342
1343static void *
1344ckmalloc(size_t nbytes)
1345{
1346 return ckrealloc(NULL, nbytes);
1347}
1348
1349static void *
1350ckzalloc(size_t nbytes)
1351{
1352 return memset(ckmalloc(nbytes), 0, nbytes);
1353}
1354
1355static char *
1356ckstrdup(const char *s)
1357{
1358 char *p = strdup(s);
1359 if (!p)
1360 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1361 return p;
1362}
1363#else
1364/* Using bbox equivalents. They exit if out of memory */
1365# define ckrealloc xrealloc
1366# define ckmalloc xmalloc
1367# define ckzalloc xzalloc
1368# define ckstrdup xstrdup
1369#endif
1370
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001371/*
1372 * It appears that grabstackstr() will barf with such alignments
1373 * because stalloc() will return a string allocated in a new stackblock.
1374 */
1375#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1376enum {
1377 /* Most machines require the value returned from malloc to be aligned
1378 * in some way. The following macro will get this right
1379 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001380 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001381 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001382 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001383};
1384
1385struct stack_block {
1386 struct stack_block *prev;
1387 char space[MINSIZE];
1388};
1389
1390struct stackmark {
1391 struct stack_block *stackp;
1392 char *stacknxt;
1393 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001394};
1395
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001396
Denis Vlasenko01631112007-12-16 17:20:38 +00001397struct globals_memstack {
1398 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001399 char *g_stacknxt; // = stackbase.space;
1400 char *sstrend; // = stackbase.space + MINSIZE;
1401 size_t g_stacknleft; // = MINSIZE;
1402 int herefd; // = -1;
1403 struct stack_block stackbase;
1404};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001405extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1406#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001407#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001408#define g_stacknxt (G_memstack.g_stacknxt )
1409#define sstrend (G_memstack.sstrend )
1410#define g_stacknleft (G_memstack.g_stacknleft)
1411#define herefd (G_memstack.herefd )
1412#define stackbase (G_memstack.stackbase )
1413#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001414 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1415 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001416 g_stackp = &stackbase; \
1417 g_stacknxt = stackbase.space; \
1418 g_stacknleft = MINSIZE; \
1419 sstrend = stackbase.space + MINSIZE; \
1420 herefd = -1; \
1421} while (0)
1422
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001423
Denis Vlasenko01631112007-12-16 17:20:38 +00001424#define stackblock() ((void *)g_stacknxt)
1425#define stackblocksize() g_stacknleft
1426
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001427/*
1428 * Parse trees for commands are allocated in lifo order, so we use a stack
1429 * to make this more efficient, and also to avoid all sorts of exception
1430 * handling code to handle interrupts in the middle of a parse.
1431 *
1432 * The size 504 was chosen because the Ultrix malloc handles that size
1433 * well.
1434 */
1435static void *
1436stalloc(size_t nbytes)
1437{
1438 char *p;
1439 size_t aligned;
1440
1441 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001442 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001443 size_t len;
1444 size_t blocksize;
1445 struct stack_block *sp;
1446
1447 blocksize = aligned;
1448 if (blocksize < MINSIZE)
1449 blocksize = MINSIZE;
1450 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1451 if (len < blocksize)
1452 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1453 INT_OFF;
1454 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001455 sp->prev = g_stackp;
1456 g_stacknxt = sp->space;
1457 g_stacknleft = blocksize;
1458 sstrend = g_stacknxt + blocksize;
1459 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001460 INT_ON;
1461 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001462 p = g_stacknxt;
1463 g_stacknxt += aligned;
1464 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001465 return p;
1466}
1467
Denis Vlasenko597906c2008-02-20 16:38:54 +00001468static void *
1469stzalloc(size_t nbytes)
1470{
1471 return memset(stalloc(nbytes), 0, nbytes);
1472}
1473
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001474static void
1475stunalloc(void *p)
1476{
1477#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001478 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001479 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001480 abort();
1481 }
1482#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001483 g_stacknleft += g_stacknxt - (char *)p;
1484 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001485}
1486
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001487/*
1488 * Like strdup but works with the ash stack.
1489 */
1490static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001491sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001492{
1493 size_t len = strlen(p) + 1;
1494 return memcpy(stalloc(len), p, len);
1495}
1496
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001497static void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001498grabstackblock(size_t len)
1499{
1500 len = SHELL_ALIGN(len);
1501 g_stacknxt += len;
1502 g_stacknleft -= len;
1503}
1504
1505static void
1506pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001507{
Denis Vlasenko01631112007-12-16 17:20:38 +00001508 mark->stackp = g_stackp;
1509 mark->stacknxt = g_stacknxt;
1510 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001511 grabstackblock(len);
1512}
1513
1514static void
1515setstackmark(struct stackmark *mark)
1516{
1517 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001518}
1519
1520static void
1521popstackmark(struct stackmark *mark)
1522{
1523 struct stack_block *sp;
1524
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001525 if (!mark->stackp)
1526 return;
1527
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001528 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001529 while (g_stackp != mark->stackp) {
1530 sp = g_stackp;
1531 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001532 free(sp);
1533 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001534 g_stacknxt = mark->stacknxt;
1535 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001536 sstrend = mark->stacknxt + mark->stacknleft;
1537 INT_ON;
1538}
1539
1540/*
1541 * When the parser reads in a string, it wants to stick the string on the
1542 * stack and only adjust the stack pointer when it knows how big the
1543 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1544 * of space on top of the stack and stackblocklen returns the length of
1545 * this block. Growstackblock will grow this space by at least one byte,
1546 * possibly moving it (like realloc). Grabstackblock actually allocates the
1547 * part of the block that has been used.
1548 */
1549static void
1550growstackblock(void)
1551{
1552 size_t newlen;
1553
Denis Vlasenko01631112007-12-16 17:20:38 +00001554 newlen = g_stacknleft * 2;
1555 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001556 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1557 if (newlen < 128)
1558 newlen += 128;
1559
Denis Vlasenko01631112007-12-16 17:20:38 +00001560 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001561 struct stack_block *sp;
1562 struct stack_block *prevstackp;
1563 size_t grosslen;
1564
1565 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001566 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001567 prevstackp = sp->prev;
1568 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1569 sp = ckrealloc(sp, grosslen);
1570 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001571 g_stackp = sp;
1572 g_stacknxt = sp->space;
1573 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001574 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001575 INT_ON;
1576 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001577 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001578 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001579 char *p = stalloc(newlen);
1580
1581 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001582 g_stacknxt = memcpy(p, oldspace, oldlen);
1583 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001584 }
1585}
1586
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001587/*
1588 * The following routines are somewhat easier to use than the above.
1589 * The user declares a variable of type STACKSTR, which may be declared
1590 * to be a register. The macro STARTSTACKSTR initializes things. Then
1591 * the user uses the macro STPUTC to add characters to the string. In
1592 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1593 * grown as necessary. When the user is done, she can just leave the
1594 * string there and refer to it using stackblock(). Or she can allocate
1595 * the space for it using grabstackstr(). If it is necessary to allow
1596 * someone else to use the stack temporarily and then continue to grow
1597 * the string, the user should use grabstack to allocate the space, and
1598 * then call ungrabstr(p) to return to the previous mode of operation.
1599 *
1600 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1601 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1602 * is space for at least one character.
1603 */
1604static void *
1605growstackstr(void)
1606{
1607 size_t len = stackblocksize();
1608 if (herefd >= 0 && len >= 1024) {
1609 full_write(herefd, stackblock(), len);
1610 return stackblock();
1611 }
1612 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001613 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001614}
1615
1616/*
1617 * Called from CHECKSTRSPACE.
1618 */
1619static char *
1620makestrspace(size_t newlen, char *p)
1621{
Denis Vlasenko01631112007-12-16 17:20:38 +00001622 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001623 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001624
1625 for (;;) {
1626 size_t nleft;
1627
1628 size = stackblocksize();
1629 nleft = size - len;
1630 if (nleft >= newlen)
1631 break;
1632 growstackblock();
1633 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001634 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001635}
1636
1637static char *
1638stack_nputstr(const char *s, size_t n, char *p)
1639{
1640 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001641 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001642 return p;
1643}
1644
1645static char *
1646stack_putstr(const char *s, char *p)
1647{
1648 return stack_nputstr(s, strlen(s), p);
1649}
1650
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001651static char *
1652_STPUTC(int c, char *p)
1653{
1654 if (p == sstrend)
1655 p = growstackstr();
1656 *p++ = c;
1657 return p;
1658}
1659
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001660#define STARTSTACKSTR(p) ((p) = stackblock())
1661#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001662#define CHECKSTRSPACE(n, p) do { \
1663 char *q = (p); \
1664 size_t l = (n); \
1665 size_t m = sstrend - q; \
1666 if (l > m) \
1667 (p) = makestrspace(l, q); \
1668} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001669#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001670#define STACKSTRNUL(p) do { \
1671 if ((p) == sstrend) \
1672 (p) = growstackstr(); \
1673 *(p) = '\0'; \
1674} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001675#define STUNPUTC(p) (--(p))
1676#define STTOPC(p) ((p)[-1])
1677#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001678
1679#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001680#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001681#define stackstrend() ((void *)sstrend)
1682
1683
1684/* ============ String helpers */
1685
1686/*
1687 * prefix -- see if pfx is a prefix of string.
1688 */
1689static char *
1690prefix(const char *string, const char *pfx)
1691{
1692 while (*pfx) {
1693 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001694 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001695 }
1696 return (char *) string;
1697}
1698
1699/*
1700 * Check for a valid number. This should be elsewhere.
1701 */
1702static int
1703is_number(const char *p)
1704{
1705 do {
1706 if (!isdigit(*p))
1707 return 0;
1708 } while (*++p != '\0');
1709 return 1;
1710}
1711
1712/*
1713 * Convert a string of digits to an integer, printing an error message on
1714 * failure.
1715 */
1716static int
1717number(const char *s)
1718{
1719 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001720 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001721 return atoi(s);
1722}
1723
1724/*
1725 * Produce a possibly single quoted string suitable as input to the shell.
1726 * The return string is allocated on the stack.
1727 */
1728static char *
1729single_quote(const char *s)
1730{
1731 char *p;
1732
1733 STARTSTACKSTR(p);
1734
1735 do {
1736 char *q;
1737 size_t len;
1738
1739 len = strchrnul(s, '\'') - s;
1740
1741 q = p = makestrspace(len + 3, p);
1742
1743 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001744 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001745 *q++ = '\'';
1746 s += len;
1747
1748 STADJUST(q - p, p);
1749
Denys Vlasenkocd716832009-11-28 22:14:02 +01001750 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001751 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001752 len = 0;
1753 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001754
1755 q = p = makestrspace(len + 3, p);
1756
1757 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001758 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001759 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001760
1761 STADJUST(q - p, p);
1762 } while (*s);
1763
Denys Vlasenkocd716832009-11-28 22:14:02 +01001764 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001765
1766 return stackblock();
1767}
1768
1769
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001770/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001771
1772static char **argptr; /* argument list for builtin commands */
1773static char *optionarg; /* set by nextopt (like getopt) */
1774static char *optptr; /* used by nextopt */
1775
1776/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001777 * XXX - should get rid of. Have all builtins use getopt(3).
1778 * The library getopt must have the BSD extension static variable
1779 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001780 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001781 * Standard option processing (a la getopt) for builtin routines.
1782 * The only argument that is passed to nextopt is the option string;
1783 * the other arguments are unnecessary. It returns the character,
1784 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001785 */
1786static int
1787nextopt(const char *optstring)
1788{
1789 char *p;
1790 const char *q;
1791 char c;
1792
1793 p = optptr;
1794 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001795 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001796 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001797 if (p == NULL)
1798 return '\0';
1799 if (*p != '-')
1800 return '\0';
1801 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001802 return '\0';
1803 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001804 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001805 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001806 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001807 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001808 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001809 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001810 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001811 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001812 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001813 if (*++q == ':')
1814 q++;
1815 }
1816 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001817 if (*p == '\0') {
1818 p = *argptr++;
1819 if (p == NULL)
1820 ash_msg_and_raise_error("no arg for -%c option", c);
1821 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001822 optionarg = p;
1823 p = NULL;
1824 }
1825 optptr = p;
1826 return c;
1827}
1828
1829
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001830/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001831
Denis Vlasenko01631112007-12-16 17:20:38 +00001832/*
1833 * The parsefile structure pointed to by the global variable parsefile
1834 * contains information about the current file being read.
1835 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001836struct shparam {
1837 int nparam; /* # of positional parameters (without $0) */
1838#if ENABLE_ASH_GETOPTS
1839 int optind; /* next parameter to be processed by getopts */
1840 int optoff; /* used by getopts */
1841#endif
1842 unsigned char malloced; /* if parameter list dynamically allocated */
1843 char **p; /* parameter list */
1844};
1845
1846/*
1847 * Free the list of positional parameters.
1848 */
1849static void
1850freeparam(volatile struct shparam *param)
1851{
Denis Vlasenko01631112007-12-16 17:20:38 +00001852 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001853 char **ap, **ap1;
1854 ap = ap1 = param->p;
1855 while (*ap)
1856 free(*ap++);
1857 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001858 }
1859}
1860
1861#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001862static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001863#endif
1864
1865struct var {
1866 struct var *next; /* next entry in hash list */
1867 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001868 const char *var_text; /* name=value */
1869 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001870 /* the variable gets set/unset */
1871};
1872
1873struct localvar {
1874 struct localvar *next; /* next local variable in list */
1875 struct var *vp; /* the variable that was made local */
1876 int flags; /* saved flags */
1877 const char *text; /* saved text */
1878};
1879
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001880/* flags */
1881#define VEXPORT 0x01 /* variable is exported */
1882#define VREADONLY 0x02 /* variable cannot be modified */
1883#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1884#define VTEXTFIXED 0x08 /* text is statically allocated */
1885#define VSTACK 0x10 /* text is allocated on the stack */
1886#define VUNSET 0x20 /* the variable is not set */
1887#define VNOFUNC 0x40 /* don't call the callback function */
1888#define VNOSET 0x80 /* do not set variable - just readonly test */
1889#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001890#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001891# define VDYNAMIC 0x200 /* dynamic variable */
1892#else
1893# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001894#endif
1895
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001896
Denis Vlasenko01631112007-12-16 17:20:38 +00001897/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001898#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001899static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001900change_lc_all(const char *value)
1901{
1902 if (value && *value != '\0')
1903 setlocale(LC_ALL, value);
1904}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001905static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001906change_lc_ctype(const char *value)
1907{
1908 if (value && *value != '\0')
1909 setlocale(LC_CTYPE, value);
1910}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001911#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001912#if ENABLE_ASH_MAIL
1913static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001914static void changemail(const char *var_value) FAST_FUNC;
1915#else
1916# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001917#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001918static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001919#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001920static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001921#endif
1922
Denis Vlasenko01631112007-12-16 17:20:38 +00001923static const struct {
1924 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001925 const char *var_text;
1926 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001927} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001928 /*
1929 * Note: VEXPORT would not work correctly here for NOFORK applets:
1930 * some environment strings may be constant.
1931 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001932 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001933#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001934 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1935 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001936#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001937 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1938 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1939 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1940 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001941#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001942 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001943#endif
1944#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001945 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001946#endif
1947#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001948 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1949 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001950#endif
1951#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001952 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001953#endif
1954};
1955
Denis Vlasenko0b769642008-07-24 07:54:57 +00001956struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001957
1958struct globals_var {
1959 struct shparam shellparam; /* $@ current positional parameters */
1960 struct redirtab *redirlist;
1961 int g_nullredirs;
1962 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1963 struct var *vartab[VTABSIZE];
1964 struct var varinit[ARRAY_SIZE(varinit_data)];
1965};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001966extern struct globals_var *const ash_ptr_to_globals_var;
1967#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001968#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001969//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001970#define g_nullredirs (G_var.g_nullredirs )
1971#define preverrout_fd (G_var.preverrout_fd)
1972#define vartab (G_var.vartab )
1973#define varinit (G_var.varinit )
1974#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001975 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001976 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1977 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001978 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001979 varinit[i].flags = varinit_data[i].flags; \
1980 varinit[i].var_text = varinit_data[i].var_text; \
1981 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001982 } \
1983} while (0)
1984
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001985#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001986#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001987# define vmail (&vifs)[1]
1988# define vmpath (&vmail)[1]
1989# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001990#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001991# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001992#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001993#define vps1 (&vpath)[1]
1994#define vps2 (&vps1)[1]
1995#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001996#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001997# define voptind (&vps4)[1]
1998# if ENABLE_ASH_RANDOM_SUPPORT
1999# define vrandom (&voptind)[1]
2000# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002001#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002002# if ENABLE_ASH_RANDOM_SUPPORT
2003# define vrandom (&vps4)[1]
2004# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002005#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002006
2007/*
2008 * The following macros access the values of the above variables.
2009 * They have to skip over the name. They return the null string
2010 * for unset variables.
2011 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002012#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002013#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002014#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002015# define mailval() (vmail.var_text + 5)
2016# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002017# define mpathset() ((vmpath.flags & VUNSET) == 0)
2018#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002019#define pathval() (vpath.var_text + 5)
2020#define ps1val() (vps1.var_text + 4)
2021#define ps2val() (vps2.var_text + 4)
2022#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002023#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002024# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002025#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002026
Denis Vlasenko01631112007-12-16 17:20:38 +00002027#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002028static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002029getoptsreset(const char *value)
2030{
2031 shellparam.optind = number(value);
2032 shellparam.optoff = -1;
2033}
2034#endif
2035
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002036/*
2037 * Compares two strings up to the first = or '\0'. The first
2038 * string must be terminated by '='; the second may be terminated by
2039 * either '=' or '\0'.
2040 */
2041static int
2042varcmp(const char *p, const char *q)
2043{
2044 int c, d;
2045
2046 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002047 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002048 goto out;
2049 p++;
2050 q++;
2051 }
2052 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002053 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002054 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002055 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002056 out:
2057 return c - d;
2058}
2059
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002060/*
2061 * Find the appropriate entry in the hash table from the name.
2062 */
2063static struct var **
2064hashvar(const char *p)
2065{
2066 unsigned hashval;
2067
2068 hashval = ((unsigned char) *p) << 4;
2069 while (*p && *p != '=')
2070 hashval += (unsigned char) *p++;
2071 return &vartab[hashval % VTABSIZE];
2072}
2073
2074static int
2075vpcmp(const void *a, const void *b)
2076{
2077 return varcmp(*(const char **)a, *(const char **)b);
2078}
2079
2080/*
2081 * This routine initializes the builtin variables.
2082 */
2083static void
2084initvar(void)
2085{
2086 struct var *vp;
2087 struct var *end;
2088 struct var **vpp;
2089
2090 /*
2091 * PS1 depends on uid
2092 */
2093#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002094 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002095#else
2096 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002097 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002098#endif
2099 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002100 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002101 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002102 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002103 vp->next = *vpp;
2104 *vpp = vp;
2105 } while (++vp < end);
2106}
2107
2108static struct var **
2109findvar(struct var **vpp, const char *name)
2110{
2111 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002112 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002113 break;
2114 }
2115 }
2116 return vpp;
2117}
2118
2119/*
2120 * Find the value of a variable. Returns NULL if not set.
2121 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002122static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002123lookupvar(const char *name)
2124{
2125 struct var *v;
2126
2127 v = *findvar(hashvar(name), name);
2128 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002129#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002130 /*
2131 * Dynamic variables are implemented roughly the same way they are
2132 * in bash. Namely, they're "special" so long as they aren't unset.
2133 * As soon as they're unset, they're no longer dynamic, and dynamic
2134 * lookup will no longer happen at that point. -- PFM.
2135 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002136 if (v->flags & VDYNAMIC)
2137 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002138#endif
2139 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002140 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002141 }
2142 return NULL;
2143}
2144
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002145static void
2146reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002147{
2148 /* Unicode support should be activated even if LANG is set
2149 * _during_ shell execution, not only if it was set when
2150 * shell was started. Therefore, re-check LANG every time:
2151 */
2152 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2153 || ENABLE_UNICODE_USING_LOCALE
2154 ) {
2155 const char *s = lookupvar("LC_ALL");
2156 if (!s) s = lookupvar("LC_CTYPE");
2157 if (!s) s = lookupvar("LANG");
2158 reinit_unicode(s);
2159 }
2160}
2161
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002162/*
2163 * Search the environment of a builtin command.
2164 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002165static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002166bltinlookup(const char *name)
2167{
2168 struct strlist *sp;
2169
2170 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002171 if (varcmp(sp->text, name) == 0)
2172 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002173 }
2174 return lookupvar(name);
2175}
2176
2177/*
2178 * Same as setvar except that the variable and value are passed in
2179 * the first argument as name=value. Since the first argument will
2180 * be actually stored in the table, it should not be a string that
2181 * will go away.
2182 * Called with interrupts off.
2183 */
2184static void
2185setvareq(char *s, int flags)
2186{
2187 struct var *vp, **vpp;
2188
2189 vpp = hashvar(s);
2190 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2191 vp = *findvar(vpp, s);
2192 if (vp) {
2193 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2194 const char *n;
2195
2196 if (flags & VNOSAVE)
2197 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002198 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002199 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2200 }
2201
2202 if (flags & VNOSET)
2203 return;
2204
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002205 if (vp->var_func && !(flags & VNOFUNC))
2206 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002207
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002208 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2209 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002210
2211 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2212 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002213 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002214 if (flags & VNOSET)
2215 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002216 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002217 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002218 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002219 *vpp = vp;
2220 }
2221 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2222 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002223 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002224 vp->flags = flags;
2225}
2226
2227/*
2228 * Set the value of a variable. The flags argument is ored with the
2229 * flags of the variable. If val is NULL, the variable is unset.
2230 */
2231static void
2232setvar(const char *name, const char *val, int flags)
2233{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002234 const char *q;
2235 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002237 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002238 size_t vallen;
2239
2240 q = endofname(name);
2241 p = strchrnul(q, '=');
2242 namelen = p - name;
2243 if (!namelen || p != q)
2244 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2245 vallen = 0;
2246 if (val == NULL) {
2247 flags |= VUNSET;
2248 } else {
2249 vallen = strlen(val);
2250 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002251
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002252 INT_OFF;
2253 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002254 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002255 if (val) {
2256 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002257 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002258 }
2259 *p = '\0';
2260 setvareq(nameeq, flags | VNOSAVE);
2261 INT_ON;
2262}
2263
Denys Vlasenko03dad222010-01-12 23:29:57 +01002264static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002265setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002266{
2267 setvar(name, val, 0);
2268}
2269
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002270#if ENABLE_ASH_GETOPTS
2271/*
2272 * Safe version of setvar, returns 1 on success 0 on failure.
2273 */
2274static int
2275setvarsafe(const char *name, const char *val, int flags)
2276{
2277 int err;
2278 volatile int saveint;
2279 struct jmploc *volatile savehandler = exception_handler;
2280 struct jmploc jmploc;
2281
2282 SAVE_INT(saveint);
2283 if (setjmp(jmploc.loc))
2284 err = 1;
2285 else {
2286 exception_handler = &jmploc;
2287 setvar(name, val, flags);
2288 err = 0;
2289 }
2290 exception_handler = savehandler;
2291 RESTORE_INT(saveint);
2292 return err;
2293}
2294#endif
2295
2296/*
2297 * Unset the specified variable.
2298 */
2299static int
2300unsetvar(const char *s)
2301{
2302 struct var **vpp;
2303 struct var *vp;
2304 int retval;
2305
2306 vpp = findvar(hashvar(s), s);
2307 vp = *vpp;
2308 retval = 2;
2309 if (vp) {
2310 int flags = vp->flags;
2311
2312 retval = 1;
2313 if (flags & VREADONLY)
2314 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002315#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002316 vp->flags &= ~VDYNAMIC;
2317#endif
2318 if (flags & VUNSET)
2319 goto ok;
2320 if ((flags & VSTRFIXED) == 0) {
2321 INT_OFF;
2322 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002323 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002324 *vpp = vp->next;
2325 free(vp);
2326 INT_ON;
2327 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002328 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002329 vp->flags &= ~VEXPORT;
2330 }
2331 ok:
2332 retval = 0;
2333 }
2334 out:
2335 return retval;
2336}
2337
2338/*
2339 * Process a linked list of variable assignments.
2340 */
2341static void
2342listsetvar(struct strlist *list_set_var, int flags)
2343{
2344 struct strlist *lp = list_set_var;
2345
2346 if (!lp)
2347 return;
2348 INT_OFF;
2349 do {
2350 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002351 lp = lp->next;
2352 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002353 INT_ON;
2354}
2355
2356/*
2357 * Generate a list of variables satisfying the given conditions.
2358 */
2359static char **
2360listvars(int on, int off, char ***end)
2361{
2362 struct var **vpp;
2363 struct var *vp;
2364 char **ep;
2365 int mask;
2366
2367 STARTSTACKSTR(ep);
2368 vpp = vartab;
2369 mask = on | off;
2370 do {
2371 for (vp = *vpp; vp; vp = vp->next) {
2372 if ((vp->flags & mask) == on) {
2373 if (ep == stackstrend())
2374 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002375 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002376 }
2377 }
2378 } while (++vpp < vartab + VTABSIZE);
2379 if (ep == stackstrend())
2380 ep = growstackstr();
2381 if (end)
2382 *end = ep;
2383 *ep++ = NULL;
2384 return grabstackstr(ep);
2385}
2386
2387
2388/* ============ Path search helper
2389 *
2390 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002391 * of the path before the first call; path_advance will update
2392 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002393 * the possible path expansions in sequence. If an option (indicated by
2394 * a percent sign) appears in the path entry then the global variable
2395 * pathopt will be set to point to it; otherwise pathopt will be set to
2396 * NULL.
2397 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002398static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002399
2400static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002401path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002402{
2403 const char *p;
2404 char *q;
2405 const char *start;
2406 size_t len;
2407
2408 if (*path == NULL)
2409 return NULL;
2410 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002411 for (p = start; *p && *p != ':' && *p != '%'; p++)
2412 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002413 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2414 while (stackblocksize() < len)
2415 growstackblock();
2416 q = stackblock();
2417 if (p != start) {
2418 memcpy(q, start, p - start);
2419 q += p - start;
2420 *q++ = '/';
2421 }
2422 strcpy(q, name);
2423 pathopt = NULL;
2424 if (*p == '%') {
2425 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002426 while (*p && *p != ':')
2427 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002428 }
2429 if (*p == ':')
2430 *path = p + 1;
2431 else
2432 *path = NULL;
2433 return stalloc(len);
2434}
2435
2436
2437/* ============ Prompt */
2438
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002439static smallint doprompt; /* if set, prompt the user */
2440static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002441
2442#if ENABLE_FEATURE_EDITING
2443static line_input_t *line_input_state;
2444static const char *cmdedit_prompt;
2445static void
2446putprompt(const char *s)
2447{
2448 if (ENABLE_ASH_EXPAND_PRMT) {
2449 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002450 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002451 return;
2452 }
2453 cmdedit_prompt = s;
2454}
2455#else
2456static void
2457putprompt(const char *s)
2458{
2459 out2str(s);
2460}
2461#endif
2462
2463#if ENABLE_ASH_EXPAND_PRMT
2464/* expandstr() needs parsing machinery, so it is far away ahead... */
2465static const char *expandstr(const char *ps);
2466#else
2467#define expandstr(s) s
2468#endif
2469
2470static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002471setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002472{
2473 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002474 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2475
2476 if (!do_set)
2477 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002478
2479 needprompt = 0;
2480
2481 switch (whichprompt) {
2482 case 1:
2483 prompt = ps1val();
2484 break;
2485 case 2:
2486 prompt = ps2val();
2487 break;
2488 default: /* 0 */
2489 prompt = nullstr;
2490 }
2491#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002492 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002493#endif
2494 putprompt(expandstr(prompt));
2495#if ENABLE_ASH_EXPAND_PRMT
2496 popstackmark(&smark);
2497#endif
2498}
2499
2500
2501/* ============ The cd and pwd commands */
2502
2503#define CD_PHYSICAL 1
2504#define CD_PRINT 2
2505
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002506static int
2507cdopt(void)
2508{
2509 int flags = 0;
2510 int i, j;
2511
2512 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002513 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002514 if (i != j) {
2515 flags ^= CD_PHYSICAL;
2516 j = i;
2517 }
2518 }
2519
2520 return flags;
2521}
2522
2523/*
2524 * Update curdir (the name of the current directory) in response to a
2525 * cd command.
2526 */
2527static const char *
2528updatepwd(const char *dir)
2529{
2530 char *new;
2531 char *p;
2532 char *cdcomppath;
2533 const char *lim;
2534
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002535 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002536 STARTSTACKSTR(new);
2537 if (*dir != '/') {
2538 if (curdir == nullstr)
2539 return 0;
2540 new = stack_putstr(curdir, new);
2541 }
2542 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002543 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002544 if (*dir != '/') {
2545 if (new[-1] != '/')
2546 USTPUTC('/', new);
2547 if (new > lim && *lim == '/')
2548 lim++;
2549 } else {
2550 USTPUTC('/', new);
2551 cdcomppath++;
2552 if (dir[1] == '/' && dir[2] != '/') {
2553 USTPUTC('/', new);
2554 cdcomppath++;
2555 lim++;
2556 }
2557 }
2558 p = strtok(cdcomppath, "/");
2559 while (p) {
2560 switch (*p) {
2561 case '.':
2562 if (p[1] == '.' && p[2] == '\0') {
2563 while (new > lim) {
2564 STUNPUTC(new);
2565 if (new[-1] == '/')
2566 break;
2567 }
2568 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002569 }
2570 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002571 break;
2572 /* fall through */
2573 default:
2574 new = stack_putstr(p, new);
2575 USTPUTC('/', new);
2576 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002577 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002578 }
2579 if (new > lim)
2580 STUNPUTC(new);
2581 *new = 0;
2582 return stackblock();
2583}
2584
2585/*
2586 * Find out what the current directory is. If we already know the current
2587 * directory, this routine returns immediately.
2588 */
2589static char *
2590getpwd(void)
2591{
Denis Vlasenko01631112007-12-16 17:20:38 +00002592 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002593 return dir ? dir : nullstr;
2594}
2595
2596static void
2597setpwd(const char *val, int setold)
2598{
2599 char *oldcur, *dir;
2600
2601 oldcur = dir = curdir;
2602
2603 if (setold) {
2604 setvar("OLDPWD", oldcur, VEXPORT);
2605 }
2606 INT_OFF;
2607 if (physdir != nullstr) {
2608 if (physdir != oldcur)
2609 free(physdir);
2610 physdir = nullstr;
2611 }
2612 if (oldcur == val || !val) {
2613 char *s = getpwd();
2614 physdir = s;
2615 if (!val)
2616 dir = s;
2617 } else
2618 dir = ckstrdup(val);
2619 if (oldcur != dir && oldcur != nullstr) {
2620 free(oldcur);
2621 }
2622 curdir = dir;
2623 INT_ON;
2624 setvar("PWD", dir, VEXPORT);
2625}
2626
2627static void hashcd(void);
2628
2629/*
2630 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2631 * know that the current directory has changed.
2632 */
2633static int
2634docd(const char *dest, int flags)
2635{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002636 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002637 int err;
2638
2639 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2640
2641 INT_OFF;
2642 if (!(flags & CD_PHYSICAL)) {
2643 dir = updatepwd(dest);
2644 if (dir)
2645 dest = dir;
2646 }
2647 err = chdir(dest);
2648 if (err)
2649 goto out;
2650 setpwd(dir, 1);
2651 hashcd();
2652 out:
2653 INT_ON;
2654 return err;
2655}
2656
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002657static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002658cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002659{
2660 const char *dest;
2661 const char *path;
2662 const char *p;
2663 char c;
2664 struct stat statb;
2665 int flags;
2666
2667 flags = cdopt();
2668 dest = *argptr;
2669 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002670 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002671 else if (LONE_DASH(dest)) {
2672 dest = bltinlookup("OLDPWD");
2673 flags |= CD_PRINT;
2674 }
2675 if (!dest)
2676 dest = nullstr;
2677 if (*dest == '/')
2678 goto step7;
2679 if (*dest == '.') {
2680 c = dest[1];
2681 dotdot:
2682 switch (c) {
2683 case '\0':
2684 case '/':
2685 goto step6;
2686 case '.':
2687 c = dest[2];
2688 if (c != '.')
2689 goto dotdot;
2690 }
2691 }
2692 if (!*dest)
2693 dest = ".";
2694 path = bltinlookup("CDPATH");
2695 if (!path) {
2696 step6:
2697 step7:
2698 p = dest;
2699 goto docd;
2700 }
2701 do {
2702 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002703 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002704 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2705 if (c && c != ':')
2706 flags |= CD_PRINT;
2707 docd:
2708 if (!docd(p, flags))
2709 goto out;
2710 break;
2711 }
2712 } while (path);
2713 ash_msg_and_raise_error("can't cd to %s", dest);
2714 /* NOTREACHED */
2715 out:
2716 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002717 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002718 return 0;
2719}
2720
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002721static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002722pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002723{
2724 int flags;
2725 const char *dir = curdir;
2726
2727 flags = cdopt();
2728 if (flags) {
2729 if (physdir == nullstr)
2730 setpwd(dir, 0);
2731 dir = physdir;
2732 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002733 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002734 return 0;
2735}
2736
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002737
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002738/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002739
Denis Vlasenko834dee72008-10-07 09:18:30 +00002740
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002741#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002742
Eric Andersenc470f442003-07-28 09:56:35 +00002743/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002744#define CWORD 0 /* character is nothing special */
2745#define CNL 1 /* newline character */
2746#define CBACK 2 /* a backslash character */
2747#define CSQUOTE 3 /* single quote */
2748#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002749#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002750#define CBQUOTE 6 /* backwards single quote */
2751#define CVAR 7 /* a dollar sign */
2752#define CENDVAR 8 /* a '}' character */
2753#define CLP 9 /* a left paren in arithmetic */
2754#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002755#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002756#define CCTL 12 /* like CWORD, except it must be escaped */
2757#define CSPCL 13 /* these terminate a word */
2758#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002759
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002760#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002761#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002762# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002763#endif
2764
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002765#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002766
Mike Frysinger98c52642009-04-02 10:02:37 +00002767#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002768# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002769#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002770# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002771#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002772static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002773#if ENABLE_ASH_ALIAS
2774 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2775#endif
2776 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2777 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2778 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2779 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2780 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2781 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2782 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2783 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2784 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2785 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2786 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002787#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002788 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2789 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2790 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2791#endif
2792#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002793};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002794/* Constants below must match table above */
2795enum {
2796#if ENABLE_ASH_ALIAS
2797 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2798#endif
2799 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2800 CNL_CNL_CNL_CNL , /* 2 */
2801 CWORD_CCTL_CCTL_CWORD , /* 3 */
2802 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2803 CVAR_CVAR_CWORD_CVAR , /* 5 */
2804 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2805 CSPCL_CWORD_CWORD_CLP , /* 7 */
2806 CSPCL_CWORD_CWORD_CRP , /* 8 */
2807 CBACK_CBACK_CCTL_CBACK , /* 9 */
2808 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2809 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2810 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2811 CWORD_CWORD_CWORD_CWORD , /* 13 */
2812 CCTL_CCTL_CCTL_CCTL , /* 14 */
2813};
Eric Andersen2870d962001-07-02 17:27:21 +00002814
Denys Vlasenkocd716832009-11-28 22:14:02 +01002815/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2816 * caller must ensure proper cast on it if c is *char_ptr!
2817 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002818/* Values for syntax param */
2819#define BASESYNTAX 0 /* not in quotes */
2820#define DQSYNTAX 1 /* in double quotes */
2821#define SQSYNTAX 2 /* in single quotes */
2822#define ARISYNTAX 3 /* in arithmetic */
2823#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002824
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002825#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002826
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002827static int
2828SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002829{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002830 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2831 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2832 /*
2833 * This causes '/' to be prepended with CTLESC in dquoted string,
2834 * making "./file"* treated incorrectly because we feed
2835 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2836 * The "homegrown" glob implementation is okay with that,
2837 * but glibc one isn't. With '/' always treated as CWORD,
2838 * both work fine.
2839 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002840# if ENABLE_ASH_ALIAS
2841 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002842 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002843 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002844 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2845 11, 3 /* "}~" */
2846 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002847# else
2848 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002849 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002850 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002851 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2852 10, 2 /* "}~" */
2853 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002854# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002855 const char *s;
2856 int indx;
2857
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002858 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002859 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002860# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002861 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002862 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002863 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002864# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002865 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002866 /* Cast is purely for paranoia here,
2867 * just in case someone passed signed char to us */
2868 if ((unsigned char)c >= CTL_FIRST
2869 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002870 ) {
2871 return CCTL;
2872 }
2873 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002874 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002875 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002876 indx = syntax_index_table[s - spec_symbls];
2877 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002878 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002879}
2880
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002881#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002882
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002883static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002884 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002885 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2895 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2896 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2900 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2901 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2902 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2903 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2904 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2905 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2906 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2907 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2908 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2909 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2910 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2911 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2912 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2913 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2914 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2915 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2916 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2917 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2918 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2919 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2920 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2922 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2924 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2925 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2926 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2927 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2928 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2930 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2931 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002932/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2933 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002934 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2945 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2946 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2947 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2948 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2949 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2950 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2978 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2979 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2980 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2983 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2993 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2994 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2995 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2996 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2997 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2998 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2999 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
3000 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
3001 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
3002 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
3003 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
3004 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
3005 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
3006 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
3007 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
3008 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
3009 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
3010 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
3011 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
3012 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
3013 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
3014 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
3016 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
3017 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3018 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3019 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3020 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3021 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3022 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3023 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3124 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3125 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3126 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3127 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3128 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3129 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3130 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3131 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3132 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3133 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3134 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3135 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3136 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3137 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3138 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3139 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3140 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3141 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003142 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003143# if ENABLE_ASH_ALIAS
3144 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3145# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003146};
3147
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003148# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003149
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003150#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003151
Eric Andersen2870d962001-07-02 17:27:21 +00003152
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003153/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003154
Denis Vlasenko131ae172007-02-18 13:00:19 +00003155#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003156
3157#define ALIASINUSE 1
3158#define ALIASDEAD 2
3159
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003160struct alias {
3161 struct alias *next;
3162 char *name;
3163 char *val;
3164 int flag;
3165};
3166
Denis Vlasenko01631112007-12-16 17:20:38 +00003167
3168static struct alias **atab; // [ATABSIZE];
3169#define INIT_G_alias() do { \
3170 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3171} while (0)
3172
Eric Andersen2870d962001-07-02 17:27:21 +00003173
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003174static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003175__lookupalias(const char *name)
3176{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003177 unsigned int hashval;
3178 struct alias **app;
3179 const char *p;
3180 unsigned int ch;
3181
3182 p = name;
3183
3184 ch = (unsigned char)*p;
3185 hashval = ch << 4;
3186 while (ch) {
3187 hashval += ch;
3188 ch = (unsigned char)*++p;
3189 }
3190 app = &atab[hashval % ATABSIZE];
3191
3192 for (; *app; app = &(*app)->next) {
3193 if (strcmp(name, (*app)->name) == 0) {
3194 break;
3195 }
3196 }
3197
3198 return app;
3199}
3200
3201static struct alias *
3202lookupalias(const char *name, int check)
3203{
3204 struct alias *ap = *__lookupalias(name);
3205
3206 if (check && ap && (ap->flag & ALIASINUSE))
3207 return NULL;
3208 return ap;
3209}
3210
3211static struct alias *
3212freealias(struct alias *ap)
3213{
3214 struct alias *next;
3215
3216 if (ap->flag & ALIASINUSE) {
3217 ap->flag |= ALIASDEAD;
3218 return ap;
3219 }
3220
3221 next = ap->next;
3222 free(ap->name);
3223 free(ap->val);
3224 free(ap);
3225 return next;
3226}
Eric Andersencb57d552001-06-28 07:25:16 +00003227
Eric Andersenc470f442003-07-28 09:56:35 +00003228static void
3229setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003230{
3231 struct alias *ap, **app;
3232
3233 app = __lookupalias(name);
3234 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003235 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003236 if (ap) {
3237 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003238 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003239 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003240 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003241 ap->flag &= ~ALIASDEAD;
3242 } else {
3243 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003244 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003245 ap->name = ckstrdup(name);
3246 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003247 /*ap->flag = 0; - ckzalloc did it */
3248 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003249 *app = ap;
3250 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003251 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003252}
3253
Eric Andersenc470f442003-07-28 09:56:35 +00003254static int
3255unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003256{
Eric Andersencb57d552001-06-28 07:25:16 +00003257 struct alias **app;
3258
3259 app = __lookupalias(name);
3260
3261 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003262 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003263 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003264 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003265 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003266 }
3267
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003268 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003269}
3270
Eric Andersenc470f442003-07-28 09:56:35 +00003271static void
3272rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003273{
Eric Andersencb57d552001-06-28 07:25:16 +00003274 struct alias *ap, **app;
3275 int i;
3276
Denis Vlasenkob012b102007-02-19 22:43:01 +00003277 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003278 for (i = 0; i < ATABSIZE; i++) {
3279 app = &atab[i];
3280 for (ap = *app; ap; ap = *app) {
3281 *app = freealias(*app);
3282 if (ap == *app) {
3283 app = &ap->next;
3284 }
3285 }
3286 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003287 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003288}
3289
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003290static void
3291printalias(const struct alias *ap)
3292{
3293 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3294}
3295
Eric Andersencb57d552001-06-28 07:25:16 +00003296/*
3297 * TODO - sort output
3298 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003299static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003300aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003301{
3302 char *n, *v;
3303 int ret = 0;
3304 struct alias *ap;
3305
Denis Vlasenko68404f12008-03-17 09:00:54 +00003306 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003307 int i;
3308
Denis Vlasenko68404f12008-03-17 09:00:54 +00003309 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003310 for (ap = atab[i]; ap; ap = ap->next) {
3311 printalias(ap);
3312 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003313 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003314 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003315 }
3316 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003317 v = strchr(n+1, '=');
3318 if (v == NULL) { /* n+1: funny ksh stuff */
3319 ap = *__lookupalias(n);
3320 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003321 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003322 ret = 1;
3323 } else
3324 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003325 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003326 *v++ = '\0';
3327 setalias(n, v);
3328 }
3329 }
3330
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003331 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003332}
3333
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003334static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003335unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003336{
3337 int i;
3338
3339 while ((i = nextopt("a")) != '\0') {
3340 if (i == 'a') {
3341 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003342 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003343 }
3344 }
3345 for (i = 0; *argptr; argptr++) {
3346 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003347 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003348 i = 1;
3349 }
3350 }
3351
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003352 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003353}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003354
Denis Vlasenko131ae172007-02-18 13:00:19 +00003355#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003356
Eric Andersenc470f442003-07-28 09:56:35 +00003357
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003358/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003359#define FORK_FG 0
3360#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003361#define FORK_NOJOB 2
3362
3363/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003364#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3365#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3366#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003367#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003368
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003369/*
3370 * A job structure contains information about a job. A job is either a
3371 * single process or a set of processes contained in a pipeline. In the
3372 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3373 * array of pids.
3374 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003375struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003376 pid_t ps_pid; /* process id */
3377 int ps_status; /* last process status from wait() */
3378 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003379};
3380
3381struct job {
3382 struct procstat ps0; /* status of process */
3383 struct procstat *ps; /* status or processes when more than one */
3384#if JOBS
3385 int stopstatus; /* status of a stopped job */
3386#endif
3387 uint32_t
3388 nprocs: 16, /* number of processes */
3389 state: 8,
3390#define JOBRUNNING 0 /* at least one proc running */
3391#define JOBSTOPPED 1 /* all procs are stopped */
3392#define JOBDONE 2 /* all procs are completed */
3393#if JOBS
3394 sigint: 1, /* job was killed by SIGINT */
3395 jobctl: 1, /* job running under job control */
3396#endif
3397 waited: 1, /* true if this entry has been waited for */
3398 used: 1, /* true if this entry is in used */
3399 changed: 1; /* true if status has changed */
3400 struct job *prev_job; /* previous job */
3401};
3402
Denis Vlasenko68404f12008-03-17 09:00:54 +00003403static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003404static int forkshell(struct job *, union node *, int);
3405static int waitforjob(struct job *);
3406
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003407#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003408enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003409#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003410#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003411static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003412static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003413#endif
3414
3415/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003416 * Ignore a signal.
3417 */
3418static void
3419ignoresig(int signo)
3420{
3421 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3422 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3423 /* No, need to do it */
3424 signal(signo, SIG_IGN);
3425 }
3426 sigmode[signo - 1] = S_HARD_IGN;
3427}
3428
3429/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003430 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003431 */
3432static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003433signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003434{
3435 gotsig[signo - 1] = 1;
3436
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003437 if (signo == SIGINT && !trap[SIGINT]) {
3438 if (!suppress_int) {
3439 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003440 raise_interrupt(); /* does not return */
3441 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003442 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003443 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003444 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003445 }
3446}
3447
3448/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003449 * Set the signal handler for the specified signal. The routine figures
3450 * out what it should be set to.
3451 */
3452static void
3453setsignal(int signo)
3454{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003455 char *t;
3456 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003457 struct sigaction act;
3458
3459 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003460 new_act = S_DFL;
3461 if (t != NULL) { /* trap for this sig is set */
3462 new_act = S_CATCH;
3463 if (t[0] == '\0') /* trap is "": ignore this sig */
3464 new_act = S_IGN;
3465 }
3466
3467 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003468 switch (signo) {
3469 case SIGINT:
3470 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003471 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003472 break;
3473 case SIGQUIT:
3474#if DEBUG
3475 if (debug)
3476 break;
3477#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003478 /* man bash:
3479 * "In all cases, bash ignores SIGQUIT. Non-builtin
3480 * commands run by bash have signal handlers
3481 * set to the values inherited by the shell
3482 * from its parent". */
3483 new_act = S_IGN;
3484 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003485 case SIGTERM:
3486 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003487 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003488 break;
3489#if JOBS
3490 case SIGTSTP:
3491 case SIGTTOU:
3492 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003493 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003494 break;
3495#endif
3496 }
3497 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003498//TODO: if !rootshell, we reset SIGQUIT to DFL,
3499//whereas we have to restore it to what shell got on entry
3500//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003501
3502 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003503 cur_act = *t;
3504 if (cur_act == 0) {
3505 /* current setting is not yet known */
3506 if (sigaction(signo, NULL, &act)) {
3507 /* pretend it worked; maybe we should give a warning,
3508 * but other shells don't. We don't alter sigmode,
3509 * so we retry every time.
3510 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003511 return;
3512 }
3513 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003514 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003515 if (mflag
3516 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3517 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003518 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003519 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003520 }
3521 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003522 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003523 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003524
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003525 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003526 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003528 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003529 break;
3530 case S_IGN:
3531 act.sa_handler = SIG_IGN;
3532 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003533 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003534
3535 /* flags and mask matter only if !DFL and !IGN, but we do it
3536 * for all cases for more deterministic behavior:
3537 */
3538 act.sa_flags = 0;
3539 sigfillset(&act.sa_mask);
3540
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003541 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003542
3543 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003544}
3545
3546/* mode flags for set_curjob */
3547#define CUR_DELETE 2
3548#define CUR_RUNNING 1
3549#define CUR_STOPPED 0
3550
3551/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003552#define DOWAIT_NONBLOCK WNOHANG
3553#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003554
3555#if JOBS
3556/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003557static int initialpgrp; //references:2
3558static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003559#endif
3560/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003561static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003562/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003563static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003564/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003565static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003566/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003567static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003568
3569static void
3570set_curjob(struct job *jp, unsigned mode)
3571{
3572 struct job *jp1;
3573 struct job **jpp, **curp;
3574
3575 /* first remove from list */
3576 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003577 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003578 jp1 = *jpp;
3579 if (jp1 == jp)
3580 break;
3581 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003582 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003583 *jpp = jp1->prev_job;
3584
3585 /* Then re-insert in correct position */
3586 jpp = curp;
3587 switch (mode) {
3588 default:
3589#if DEBUG
3590 abort();
3591#endif
3592 case CUR_DELETE:
3593 /* job being deleted */
3594 break;
3595 case CUR_RUNNING:
3596 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003597 * put after all stopped jobs.
3598 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003599 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003600 jp1 = *jpp;
3601#if JOBS
3602 if (!jp1 || jp1->state != JOBSTOPPED)
3603#endif
3604 break;
3605 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003606 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003607 /* FALLTHROUGH */
3608#if JOBS
3609 case CUR_STOPPED:
3610#endif
3611 /* newly stopped job - becomes curjob */
3612 jp->prev_job = *jpp;
3613 *jpp = jp;
3614 break;
3615 }
3616}
3617
3618#if JOBS || DEBUG
3619static int
3620jobno(const struct job *jp)
3621{
3622 return jp - jobtab + 1;
3623}
3624#endif
3625
3626/*
3627 * Convert a job name to a job structure.
3628 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003629#if !JOBS
3630#define getjob(name, getctl) getjob(name)
3631#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003632static struct job *
3633getjob(const char *name, int getctl)
3634{
3635 struct job *jp;
3636 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003637 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003638 unsigned num;
3639 int c;
3640 const char *p;
3641 char *(*match)(const char *, const char *);
3642
3643 jp = curjob;
3644 p = name;
3645 if (!p)
3646 goto currentjob;
3647
3648 if (*p != '%')
3649 goto err;
3650
3651 c = *++p;
3652 if (!c)
3653 goto currentjob;
3654
3655 if (!p[1]) {
3656 if (c == '+' || c == '%') {
3657 currentjob:
3658 err_msg = "No current job";
3659 goto check;
3660 }
3661 if (c == '-') {
3662 if (jp)
3663 jp = jp->prev_job;
3664 err_msg = "No previous job";
3665 check:
3666 if (!jp)
3667 goto err;
3668 goto gotit;
3669 }
3670 }
3671
3672 if (is_number(p)) {
3673 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003674 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003675 jp = jobtab + num - 1;
3676 if (jp->used)
3677 goto gotit;
3678 goto err;
3679 }
3680 }
3681
3682 match = prefix;
3683 if (*p == '?') {
3684 match = strstr;
3685 p++;
3686 }
3687
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003688 found = NULL;
3689 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003690 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003691 if (found)
3692 goto err;
3693 found = jp;
3694 err_msg = "%s: ambiguous";
3695 }
3696 jp = jp->prev_job;
3697 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003698 if (!found)
3699 goto err;
3700 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003701
3702 gotit:
3703#if JOBS
3704 err_msg = "job %s not created under job control";
3705 if (getctl && jp->jobctl == 0)
3706 goto err;
3707#endif
3708 return jp;
3709 err:
3710 ash_msg_and_raise_error(err_msg, name);
3711}
3712
3713/*
3714 * Mark a job structure as unused.
3715 */
3716static void
3717freejob(struct job *jp)
3718{
3719 struct procstat *ps;
3720 int i;
3721
3722 INT_OFF;
3723 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003724 if (ps->ps_cmd != nullstr)
3725 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003726 }
3727 if (jp->ps != &jp->ps0)
3728 free(jp->ps);
3729 jp->used = 0;
3730 set_curjob(jp, CUR_DELETE);
3731 INT_ON;
3732}
3733
3734#if JOBS
3735static void
3736xtcsetpgrp(int fd, pid_t pgrp)
3737{
3738 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003739 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003740}
3741
3742/*
3743 * Turn job control on and off.
3744 *
3745 * Note: This code assumes that the third arg to ioctl is a character
3746 * pointer, which is true on Berkeley systems but not System V. Since
3747 * System V doesn't have job control yet, this isn't a problem now.
3748 *
3749 * Called with interrupts off.
3750 */
3751static void
3752setjobctl(int on)
3753{
3754 int fd;
3755 int pgrp;
3756
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003757 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003758 return;
3759 if (on) {
3760 int ofd;
3761 ofd = fd = open(_PATH_TTY, O_RDWR);
3762 if (fd < 0) {
3763 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3764 * That sometimes helps to acquire controlling tty.
3765 * Obviously, a workaround for bugs when someone
3766 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003767 fd = 2;
3768 while (!isatty(fd))
3769 if (--fd < 0)
3770 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003771 }
3772 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003773 if (ofd >= 0)
3774 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003775 if (fd < 0)
3776 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003777 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003778 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003779 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003780 pgrp = tcgetpgrp(fd);
3781 if (pgrp < 0) {
3782 out:
3783 ash_msg("can't access tty; job control turned off");
3784 mflag = on = 0;
3785 goto close;
3786 }
3787 if (pgrp == getpgrp())
3788 break;
3789 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003790 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003791 initialpgrp = pgrp;
3792
3793 setsignal(SIGTSTP);
3794 setsignal(SIGTTOU);
3795 setsignal(SIGTTIN);
3796 pgrp = rootpid;
3797 setpgid(0, pgrp);
3798 xtcsetpgrp(fd, pgrp);
3799 } else {
3800 /* turning job control off */
3801 fd = ttyfd;
3802 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003803 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003804 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003805 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003806 setpgid(0, pgrp);
3807 setsignal(SIGTSTP);
3808 setsignal(SIGTTOU);
3809 setsignal(SIGTTIN);
3810 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003811 if (fd >= 0)
3812 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003813 fd = -1;
3814 }
3815 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003816 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003817}
3818
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003819static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003820killcmd(int argc, char **argv)
3821{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003822 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003823 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003824 do {
3825 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003826 /*
3827 * "kill %N" - job kill
3828 * Converting to pgrp / pid kill
3829 */
3830 struct job *jp;
3831 char *dst;
3832 int j, n;
3833
3834 jp = getjob(argv[i], 0);
3835 /*
3836 * In jobs started under job control, we signal
3837 * entire process group by kill -PGRP_ID.
3838 * This happens, f.e., in interactive shell.
3839 *
3840 * Otherwise, we signal each child via
3841 * kill PID1 PID2 PID3.
3842 * Testcases:
3843 * sh -c 'sleep 1|sleep 1 & kill %1'
3844 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3845 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3846 */
3847 n = jp->nprocs; /* can't be 0 (I hope) */
3848 if (jp->jobctl)
3849 n = 1;
3850 dst = alloca(n * sizeof(int)*4);
3851 argv[i] = dst;
3852 for (j = 0; j < n; j++) {
3853 struct procstat *ps = &jp->ps[j];
3854 /* Skip non-running and not-stopped members
3855 * (i.e. dead members) of the job
3856 */
3857 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3858 continue;
3859 /*
3860 * kill_main has matching code to expect
3861 * leading space. Needed to not confuse
3862 * negative pids with "kill -SIGNAL_NO" syntax
3863 */
3864 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3865 }
3866 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003867 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003868 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003869 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003870 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003871}
3872
3873static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003874showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003875{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003876 struct procstat *ps;
3877 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003878
Denys Vlasenko285ad152009-12-04 23:02:27 +01003879 psend = jp->ps + jp->nprocs;
3880 for (ps = jp->ps + 1; ps < psend; ps++)
3881 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003882 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883 flush_stdout_stderr();
3884}
3885
3886
3887static int
3888restartjob(struct job *jp, int mode)
3889{
3890 struct procstat *ps;
3891 int i;
3892 int status;
3893 pid_t pgid;
3894
3895 INT_OFF;
3896 if (jp->state == JOBDONE)
3897 goto out;
3898 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003899 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003900 if (mode == FORK_FG)
3901 xtcsetpgrp(ttyfd, pgid);
3902 killpg(pgid, SIGCONT);
3903 ps = jp->ps;
3904 i = jp->nprocs;
3905 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003906 if (WIFSTOPPED(ps->ps_status)) {
3907 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003908 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003909 ps++;
3910 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003911 out:
3912 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3913 INT_ON;
3914 return status;
3915}
3916
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003917static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003918fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003919{
3920 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003921 int mode;
3922 int retval;
3923
3924 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3925 nextopt(nullstr);
3926 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003927 do {
3928 jp = getjob(*argv, 1);
3929 if (mode == FORK_BG) {
3930 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003931 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003932 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003933 out1str(jp->ps[0].ps_cmd);
3934 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003935 retval = restartjob(jp, mode);
3936 } while (*argv && *++argv);
3937 return retval;
3938}
3939#endif
3940
3941static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003942sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003943{
3944 int col;
3945 int st;
3946
3947 col = 0;
3948 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003949 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003950 st = WSTOPSIG(status);
3951 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003952 st = WTERMSIG(status);
3953 if (sigonly) {
3954 if (st == SIGINT || st == SIGPIPE)
3955 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003956 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003957 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003958 }
3959 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003960//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003961 col = fmtstr(s, 32, strsignal(st));
3962 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003963 strcpy(s + col, " (core dumped)");
3964 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003965 }
3966 } else if (!sigonly) {
3967 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003968 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003969 }
3970 out:
3971 return col;
3972}
3973
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003974static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003975dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003976{
3977 int pid;
3978 int status;
3979 struct job *jp;
3980 struct job *thisjob;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003982 TRACE(("dowait(0x%x) called\n", wait_flags));
3983
3984 /* Do a wait system call. If job control is compiled in, we accept
3985 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3986 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003987 if (doing_jobctl)
3988 wait_flags |= WUNTRACED;
3989 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003990 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3991 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003992 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003993 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003994
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003995 INT_OFF;
3996 thisjob = NULL;
3997 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003998 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003999 struct procstat *ps;
4000 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004001 if (jp->state == JOBDONE)
4002 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004003 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004004 ps = jp->ps;
4005 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004006 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004007 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004008 TRACE(("Job %d: changing status of proc %d "
4009 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01004010 jobno(jp), pid, ps->ps_status, status));
4011 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012 thisjob = jp;
4013 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01004014 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004015 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004016#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004017 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004018 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004019 if (WIFSTOPPED(ps->ps_status)) {
4020 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004021 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004022 }
4023#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004024 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004025 if (!thisjob)
4026 continue;
4027
4028 /* Found the job where one of its processes changed its state.
4029 * Is there at least one live and running process in this job? */
4030 if (jobstate != JOBRUNNING) {
4031 /* No. All live processes in the job are stopped
4032 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4033 */
4034 thisjob->changed = 1;
4035 if (thisjob->state != jobstate) {
4036 TRACE(("Job %d: changing state from %d to %d\n",
4037 jobno(thisjob), thisjob->state, jobstate));
4038 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004039#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004040 if (jobstate == JOBSTOPPED)
4041 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004042#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004043 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004044 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004045 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004046 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004047 /* The process wasn't found in job list */
4048 if (JOBS && !WIFSTOPPED(status))
4049 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004050 out:
4051 INT_ON;
4052
4053 if (thisjob && thisjob == job) {
4054 char s[48 + 1];
4055 int len;
4056
Denys Vlasenko9c541002015-10-07 15:44:36 +02004057 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004058 if (len) {
4059 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004060 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004061 out2str(s);
4062 }
4063 }
4064 return pid;
4065}
4066
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004067static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004068blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004069{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004070 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004071 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004072 raise_exception(EXSIG);
4073 return pid;
4074}
4075
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004076#if JOBS
4077static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004078showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004079{
4080 struct procstat *ps;
4081 struct procstat *psend;
4082 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004083 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004084 char s[16 + 16 + 48];
4085 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004086
4087 ps = jp->ps;
4088
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004089 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004090 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004091 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004092 return;
4093 }
4094
4095 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004096 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004097
4098 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004099 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004100 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004101 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004102
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004103 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004104 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004105
4106 psend = ps + jp->nprocs;
4107
4108 if (jp->state == JOBRUNNING) {
4109 strcpy(s + col, "Running");
4110 col += sizeof("Running") - 1;
4111 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004112 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004113 if (jp->state == JOBSTOPPED)
4114 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004115 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004116 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004117 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004118
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004119 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4120 * or prints several "PID | <cmdN>" lines,
4121 * depending on SHOW_PIDS bit.
4122 * We do not print status of individual processes
4123 * between PID and <cmdN>. bash does it, but not very well:
4124 * first line shows overall job status, not process status,
4125 * making it impossible to know 1st process status.
4126 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004127 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004128 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004129 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004130 s[0] = '\0';
4131 col = 33;
4132 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004133 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004134 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004135 fprintf(out, "%s%*c%s%s",
4136 s,
4137 33 - col >= 0 ? 33 - col : 0, ' ',
4138 ps == jp->ps ? "" : "| ",
4139 ps->ps_cmd
4140 );
4141 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004142 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143
4144 jp->changed = 0;
4145
4146 if (jp->state == JOBDONE) {
4147 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4148 freejob(jp);
4149 }
4150}
4151
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004152/*
4153 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4154 * statuses have changed since the last call to showjobs.
4155 */
4156static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004157showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004158{
4159 struct job *jp;
4160
Denys Vlasenko883cea42009-07-11 15:31:59 +02004161 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004162
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004163 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004164 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004165 continue;
4166
4167 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004168 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004169 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004170 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004171 }
4172}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004173
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004174static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004175jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004176{
4177 int mode, m;
4178
4179 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004180 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004181 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004182 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004183 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004184 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004185 }
4186
4187 argv = argptr;
4188 if (*argv) {
4189 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004190 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004191 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004192 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004193 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004194 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004195
4196 return 0;
4197}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004198#endif /* JOBS */
4199
Michael Abbott359da5e2009-12-04 23:03:29 +01004200/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004201static int
4202getstatus(struct job *job)
4203{
4204 int status;
4205 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004206 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004207
Michael Abbott359da5e2009-12-04 23:03:29 +01004208 /* Fetch last member's status */
4209 ps = job->ps + job->nprocs - 1;
4210 status = ps->ps_status;
4211 if (pipefail) {
4212 /* "set -o pipefail" mode: use last _nonzero_ status */
4213 while (status == 0 && --ps >= job->ps)
4214 status = ps->ps_status;
4215 }
4216
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004217 retval = WEXITSTATUS(status);
4218 if (!WIFEXITED(status)) {
4219#if JOBS
4220 retval = WSTOPSIG(status);
4221 if (!WIFSTOPPED(status))
4222#endif
4223 {
4224 /* XXX: limits number of signals */
4225 retval = WTERMSIG(status);
4226#if JOBS
4227 if (retval == SIGINT)
4228 job->sigint = 1;
4229#endif
4230 }
4231 retval += 128;
4232 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004233 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004234 jobno(job), job->nprocs, status, retval));
4235 return retval;
4236}
4237
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004238static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004239waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004240{
4241 struct job *job;
4242 int retval;
4243 struct job *jp;
4244
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004245 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004246 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004247
4248 nextopt(nullstr);
4249 retval = 0;
4250
4251 argv = argptr;
4252 if (!*argv) {
4253 /* wait for all jobs */
4254 for (;;) {
4255 jp = curjob;
4256 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004257 if (!jp) /* no running procs */
4258 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004259 if (jp->state == JOBRUNNING)
4260 break;
4261 jp->waited = 1;
4262 jp = jp->prev_job;
4263 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004264 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004265 /* man bash:
4266 * "When bash is waiting for an asynchronous command via
4267 * the wait builtin, the reception of a signal for which a trap
4268 * has been set will cause the wait builtin to return immediately
4269 * with an exit status greater than 128, immediately after which
4270 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004271 *
4272 * blocking_wait_with_raise_on_sig raises signal handlers
4273 * if it gets no pid (pid < 0). However,
4274 * if child sends us a signal *and immediately exits*,
4275 * blocking_wait_with_raise_on_sig gets pid > 0
4276 * and does not handle pending_sig. Check this case: */
4277 if (pending_sig)
4278 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004279 }
4280 }
4281
4282 retval = 127;
4283 do {
4284 if (**argv != '%') {
4285 pid_t pid = number(*argv);
4286 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004287 while (1) {
4288 if (!job)
4289 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004290 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004291 break;
4292 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004293 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004294 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004295 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004296 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004297 /* loop until process terminated or stopped */
4298 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004299 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004300 job->waited = 1;
4301 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004302 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004303 } while (*++argv);
4304
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004305 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004306 return retval;
4307}
4308
4309static struct job *
4310growjobtab(void)
4311{
4312 size_t len;
4313 ptrdiff_t offset;
4314 struct job *jp, *jq;
4315
4316 len = njobs * sizeof(*jp);
4317 jq = jobtab;
4318 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4319
4320 offset = (char *)jp - (char *)jq;
4321 if (offset) {
4322 /* Relocate pointers */
4323 size_t l = len;
4324
4325 jq = (struct job *)((char *)jq + l);
4326 while (l) {
4327 l -= sizeof(*jp);
4328 jq--;
4329#define joff(p) ((struct job *)((char *)(p) + l))
4330#define jmove(p) (p) = (void *)((char *)(p) + offset)
4331 if (joff(jp)->ps == &jq->ps0)
4332 jmove(joff(jp)->ps);
4333 if (joff(jp)->prev_job)
4334 jmove(joff(jp)->prev_job);
4335 }
4336 if (curjob)
4337 jmove(curjob);
4338#undef joff
4339#undef jmove
4340 }
4341
4342 njobs += 4;
4343 jobtab = jp;
4344 jp = (struct job *)((char *)jp + len);
4345 jq = jp + 3;
4346 do {
4347 jq->used = 0;
4348 } while (--jq >= jp);
4349 return jp;
4350}
4351
4352/*
4353 * Return a new job structure.
4354 * Called with interrupts off.
4355 */
4356static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004357makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004358{
4359 int i;
4360 struct job *jp;
4361
4362 for (i = njobs, jp = jobtab; ; jp++) {
4363 if (--i < 0) {
4364 jp = growjobtab();
4365 break;
4366 }
4367 if (jp->used == 0)
4368 break;
4369 if (jp->state != JOBDONE || !jp->waited)
4370 continue;
4371#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004372 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004373 continue;
4374#endif
4375 freejob(jp);
4376 break;
4377 }
4378 memset(jp, 0, sizeof(*jp));
4379#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004380 /* jp->jobctl is a bitfield.
4381 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004382 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004383 jp->jobctl = 1;
4384#endif
4385 jp->prev_job = curjob;
4386 curjob = jp;
4387 jp->used = 1;
4388 jp->ps = &jp->ps0;
4389 if (nprocs > 1) {
4390 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4391 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004392 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004393 jobno(jp)));
4394 return jp;
4395}
4396
4397#if JOBS
4398/*
4399 * Return a string identifying a command (to be printed by the
4400 * jobs command).
4401 */
4402static char *cmdnextc;
4403
4404static void
4405cmdputs(const char *s)
4406{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004407 static const char vstype[VSTYPE + 1][3] = {
4408 "", "}", "-", "+", "?", "=",
4409 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004410 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004411 };
4412
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004413 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004414 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004415 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004416 unsigned char c;
4417 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004418 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004419
Denys Vlasenko46a14772009-12-10 21:27:13 +01004420 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004421 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4422 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004423 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004424 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004425 switch (c) {
4426 case CTLESC:
4427 c = *p++;
4428 break;
4429 case CTLVAR:
4430 subtype = *p++;
4431 if ((subtype & VSTYPE) == VSLENGTH)
4432 str = "${#";
4433 else
4434 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004435 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004436 case CTLENDVAR:
4437 str = "\"}" + !(quoted & 1);
4438 quoted >>= 1;
4439 subtype = 0;
4440 goto dostr;
4441 case CTLBACKQ:
4442 str = "$(...)";
4443 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004444#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004445 case CTLARI:
4446 str = "$((";
4447 goto dostr;
4448 case CTLENDARI:
4449 str = "))";
4450 goto dostr;
4451#endif
4452 case CTLQUOTEMARK:
4453 quoted ^= 1;
4454 c = '"';
4455 break;
4456 case '=':
4457 if (subtype == 0)
4458 break;
4459 if ((subtype & VSTYPE) != VSNORMAL)
4460 quoted <<= 1;
4461 str = vstype[subtype & VSTYPE];
4462 if (subtype & VSNUL)
4463 c = ':';
4464 else
4465 goto checkstr;
4466 break;
4467 case '\'':
4468 case '\\':
4469 case '"':
4470 case '$':
4471 /* These can only happen inside quotes */
4472 cc[0] = c;
4473 str = cc;
4474 c = '\\';
4475 break;
4476 default:
4477 break;
4478 }
4479 USTPUTC(c, nextc);
4480 checkstr:
4481 if (!str)
4482 continue;
4483 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004484 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004485 USTPUTC(c, nextc);
4486 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004487 } /* while *p++ not NUL */
4488
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004489 if (quoted & 1) {
4490 USTPUTC('"', nextc);
4491 }
4492 *nextc = 0;
4493 cmdnextc = nextc;
4494}
4495
4496/* cmdtxt() and cmdlist() call each other */
4497static void cmdtxt(union node *n);
4498
4499static void
4500cmdlist(union node *np, int sep)
4501{
4502 for (; np; np = np->narg.next) {
4503 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004504 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004505 cmdtxt(np);
4506 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004507 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004508 }
4509}
4510
4511static void
4512cmdtxt(union node *n)
4513{
4514 union node *np;
4515 struct nodelist *lp;
4516 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004517
4518 if (!n)
4519 return;
4520 switch (n->type) {
4521 default:
4522#if DEBUG
4523 abort();
4524#endif
4525 case NPIPE:
4526 lp = n->npipe.cmdlist;
4527 for (;;) {
4528 cmdtxt(lp->n);
4529 lp = lp->next;
4530 if (!lp)
4531 break;
4532 cmdputs(" | ");
4533 }
4534 break;
4535 case NSEMI:
4536 p = "; ";
4537 goto binop;
4538 case NAND:
4539 p = " && ";
4540 goto binop;
4541 case NOR:
4542 p = " || ";
4543 binop:
4544 cmdtxt(n->nbinary.ch1);
4545 cmdputs(p);
4546 n = n->nbinary.ch2;
4547 goto donode;
4548 case NREDIR:
4549 case NBACKGND:
4550 n = n->nredir.n;
4551 goto donode;
4552 case NNOT:
4553 cmdputs("!");
4554 n = n->nnot.com;
4555 donode:
4556 cmdtxt(n);
4557 break;
4558 case NIF:
4559 cmdputs("if ");
4560 cmdtxt(n->nif.test);
4561 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004562 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004563 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004564 cmdputs("; else ");
4565 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004566 } else {
4567 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004568 }
4569 p = "; fi";
4570 goto dotail;
4571 case NSUBSHELL:
4572 cmdputs("(");
4573 n = n->nredir.n;
4574 p = ")";
4575 goto dotail;
4576 case NWHILE:
4577 p = "while ";
4578 goto until;
4579 case NUNTIL:
4580 p = "until ";
4581 until:
4582 cmdputs(p);
4583 cmdtxt(n->nbinary.ch1);
4584 n = n->nbinary.ch2;
4585 p = "; done";
4586 dodo:
4587 cmdputs("; do ");
4588 dotail:
4589 cmdtxt(n);
4590 goto dotail2;
4591 case NFOR:
4592 cmdputs("for ");
4593 cmdputs(n->nfor.var);
4594 cmdputs(" in ");
4595 cmdlist(n->nfor.args, 1);
4596 n = n->nfor.body;
4597 p = "; done";
4598 goto dodo;
4599 case NDEFUN:
4600 cmdputs(n->narg.text);
4601 p = "() { ... }";
4602 goto dotail2;
4603 case NCMD:
4604 cmdlist(n->ncmd.args, 1);
4605 cmdlist(n->ncmd.redirect, 0);
4606 break;
4607 case NARG:
4608 p = n->narg.text;
4609 dotail2:
4610 cmdputs(p);
4611 break;
4612 case NHERE:
4613 case NXHERE:
4614 p = "<<...";
4615 goto dotail2;
4616 case NCASE:
4617 cmdputs("case ");
4618 cmdputs(n->ncase.expr->narg.text);
4619 cmdputs(" in ");
4620 for (np = n->ncase.cases; np; np = np->nclist.next) {
4621 cmdtxt(np->nclist.pattern);
4622 cmdputs(") ");
4623 cmdtxt(np->nclist.body);
4624 cmdputs(";; ");
4625 }
4626 p = "esac";
4627 goto dotail2;
4628 case NTO:
4629 p = ">";
4630 goto redir;
4631 case NCLOBBER:
4632 p = ">|";
4633 goto redir;
4634 case NAPPEND:
4635 p = ">>";
4636 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004637#if ENABLE_ASH_BASH_COMPAT
4638 case NTO2:
4639#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004640 case NTOFD:
4641 p = ">&";
4642 goto redir;
4643 case NFROM:
4644 p = "<";
4645 goto redir;
4646 case NFROMFD:
4647 p = "<&";
4648 goto redir;
4649 case NFROMTO:
4650 p = "<>";
4651 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004652 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004653 cmdputs(p);
4654 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004655 cmdputs(utoa(n->ndup.dupfd));
4656 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004657 }
4658 n = n->nfile.fname;
4659 goto donode;
4660 }
4661}
4662
4663static char *
4664commandtext(union node *n)
4665{
4666 char *name;
4667
4668 STARTSTACKSTR(cmdnextc);
4669 cmdtxt(n);
4670 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004671 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004672 return ckstrdup(name);
4673}
4674#endif /* JOBS */
4675
4676/*
4677 * Fork off a subshell. If we are doing job control, give the subshell its
4678 * own process group. Jp is a job structure that the job is to be added to.
4679 * N is the command that will be evaluated by the child. Both jp and n may
4680 * be NULL. The mode parameter can be one of the following:
4681 * FORK_FG - Fork off a foreground process.
4682 * FORK_BG - Fork off a background process.
4683 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4684 * process group even if job control is on.
4685 *
4686 * When job control is turned off, background processes have their standard
4687 * input redirected to /dev/null (except for the second and later processes
4688 * in a pipeline).
4689 *
4690 * Called with interrupts off.
4691 */
4692/*
4693 * Clear traps on a fork.
4694 */
4695static void
4696clear_traps(void)
4697{
4698 char **tp;
4699
4700 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004701 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004702 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004703 if (trap_ptr == trap)
4704 free(*tp);
4705 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004706 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004707 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004708 setsignal(tp - trap);
4709 INT_ON;
4710 }
4711 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004712 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004713}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004714
4715/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004716static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004717
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004718/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004719static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004720forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004721{
4722 int oldlvl;
4723
4724 TRACE(("Child shell %d\n", getpid()));
4725 oldlvl = shlvl;
4726 shlvl++;
4727
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004728 /* man bash: "Non-builtin commands run by bash have signal handlers
4729 * set to the values inherited by the shell from its parent".
4730 * Do we do it correctly? */
4731
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004732 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004733
4734 if (mode == FORK_NOJOB /* is it `xxx` ? */
4735 && n && n->type == NCMD /* is it single cmd? */
4736 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004737 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004738 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4739 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4740 ) {
4741 TRACE(("Trap hack\n"));
4742 /* Awful hack for `trap` or $(trap).
4743 *
4744 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4745 * contains an example where "trap" is executed in a subshell:
4746 *
4747 * save_traps=$(trap)
4748 * ...
4749 * eval "$save_traps"
4750 *
4751 * Standard does not say that "trap" in subshell shall print
4752 * parent shell's traps. It only says that its output
4753 * must have suitable form, but then, in the above example
4754 * (which is not supposed to be normative), it implies that.
4755 *
4756 * bash (and probably other shell) does implement it
4757 * (traps are reset to defaults, but "trap" still shows them),
4758 * but as a result, "trap" logic is hopelessly messed up:
4759 *
4760 * # trap
4761 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4762 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4763 * # true | trap <--- trap is in subshell - no output (ditto)
4764 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4765 * trap -- 'echo Ho' SIGWINCH
4766 * # echo `(trap)` <--- in subshell in subshell - output
4767 * trap -- 'echo Ho' SIGWINCH
4768 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4769 * trap -- 'echo Ho' SIGWINCH
4770 *
4771 * The rules when to forget and when to not forget traps
4772 * get really complex and nonsensical.
4773 *
4774 * Our solution: ONLY bare $(trap) or `trap` is special.
4775 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004776 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004777 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004778 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004779 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004780 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004781#if JOBS
4782 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004783 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004784 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004785 pid_t pgrp;
4786
4787 if (jp->nprocs == 0)
4788 pgrp = getpid();
4789 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004790 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004791 /* this can fail because we are doing it in the parent also */
4792 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004793 if (mode == FORK_FG)
4794 xtcsetpgrp(ttyfd, pgrp);
4795 setsignal(SIGTSTP);
4796 setsignal(SIGTTOU);
4797 } else
4798#endif
4799 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004800 /* man bash: "When job control is not in effect,
4801 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004802 ignoresig(SIGINT);
4803 ignoresig(SIGQUIT);
4804 if (jp->nprocs == 0) {
4805 close(0);
4806 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004807 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004808 }
4809 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004810 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004811 if (iflag) { /* why if iflag only? */
4812 setsignal(SIGINT);
4813 setsignal(SIGTERM);
4814 }
4815 /* man bash:
4816 * "In all cases, bash ignores SIGQUIT. Non-builtin
4817 * commands run by bash have signal handlers
4818 * set to the values inherited by the shell
4819 * from its parent".
4820 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004821 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004822 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004823#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004824 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004825 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004826 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004827 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004828 /* "jobs": we do not want to clear job list for it,
4829 * instead we remove only _its_ own_ job from job list.
4830 * This makes "jobs .... | cat" more useful.
4831 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004832 freejob(curjob);
4833 return;
4834 }
4835#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004836 for (jp = curjob; jp; jp = jp->prev_job)
4837 freejob(jp);
4838 jobless = 0;
4839}
4840
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004841/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004842#if !JOBS
4843#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4844#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004845static void
4846forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4847{
4848 TRACE(("In parent shell: child = %d\n", pid));
4849 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004850 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4851 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004852 jobless++;
4853 return;
4854 }
4855#if JOBS
4856 if (mode != FORK_NOJOB && jp->jobctl) {
4857 int pgrp;
4858
4859 if (jp->nprocs == 0)
4860 pgrp = pid;
4861 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004862 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004863 /* This can fail because we are doing it in the child also */
4864 setpgid(pid, pgrp);
4865 }
4866#endif
4867 if (mode == FORK_BG) {
4868 backgndpid = pid; /* set $! */
4869 set_curjob(jp, CUR_RUNNING);
4870 }
4871 if (jp) {
4872 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004873 ps->ps_pid = pid;
4874 ps->ps_status = -1;
4875 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004876#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004877 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004878 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004879#endif
4880 }
4881}
4882
4883static int
4884forkshell(struct job *jp, union node *n, int mode)
4885{
4886 int pid;
4887
4888 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4889 pid = fork();
4890 if (pid < 0) {
4891 TRACE(("Fork failed, errno=%d", errno));
4892 if (jp)
4893 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004894 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004895 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004896 if (pid == 0) {
4897 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004898 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004899 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004900 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004901 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004902 return pid;
4903}
4904
4905/*
4906 * Wait for job to finish.
4907 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004908 * Under job control we have the problem that while a child process
4909 * is running interrupts generated by the user are sent to the child
4910 * but not to the shell. This means that an infinite loop started by
4911 * an interactive user may be hard to kill. With job control turned off,
4912 * an interactive user may place an interactive program inside a loop.
4913 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004914 * these interrupts to also abort the loop. The approach we take here
4915 * is to have the shell ignore interrupt signals while waiting for a
4916 * foreground process to terminate, and then send itself an interrupt
4917 * signal if the child process was terminated by an interrupt signal.
4918 * Unfortunately, some programs want to do a bit of cleanup and then
4919 * exit on interrupt; unless these processes terminate themselves by
4920 * sending a signal to themselves (instead of calling exit) they will
4921 * confuse this approach.
4922 *
4923 * Called with interrupts off.
4924 */
4925static int
4926waitforjob(struct job *jp)
4927{
4928 int st;
4929
4930 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004931
4932 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004933 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004934 /* In non-interactive shells, we _can_ get
4935 * a keyboard signal here and be EINTRed,
4936 * but we just loop back, waiting for command to complete.
4937 *
4938 * man bash:
4939 * "If bash is waiting for a command to complete and receives
4940 * a signal for which a trap has been set, the trap
4941 * will not be executed until the command completes."
4942 *
4943 * Reality is that even if trap is not set, bash
4944 * will not act on the signal until command completes.
4945 * Try this. sleep5intoff.c:
4946 * #include <signal.h>
4947 * #include <unistd.h>
4948 * int main() {
4949 * sigset_t set;
4950 * sigemptyset(&set);
4951 * sigaddset(&set, SIGINT);
4952 * sigaddset(&set, SIGQUIT);
4953 * sigprocmask(SIG_BLOCK, &set, NULL);
4954 * sleep(5);
4955 * return 0;
4956 * }
4957 * $ bash -c './sleep5intoff; echo hi'
4958 * ^C^C^C^C <--- pressing ^C once a second
4959 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004960 * $ bash -c './sleep5intoff; echo hi'
4961 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4962 * $ _
4963 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004964 dowait(DOWAIT_BLOCK, jp);
4965 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004966 INT_ON;
4967
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004968 st = getstatus(jp);
4969#if JOBS
4970 if (jp->jobctl) {
4971 xtcsetpgrp(ttyfd, rootpid);
4972 /*
4973 * This is truly gross.
4974 * If we're doing job control, then we did a TIOCSPGRP which
4975 * caused us (the shell) to no longer be in the controlling
4976 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4977 * intuit from the subprocess exit status whether a SIGINT
4978 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4979 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004980 if (jp->sigint) /* TODO: do the same with all signals */
4981 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004982 }
4983 if (jp->state == JOBDONE)
4984#endif
4985 freejob(jp);
4986 return st;
4987}
4988
4989/*
4990 * return 1 if there are stopped jobs, otherwise 0
4991 */
4992static int
4993stoppedjobs(void)
4994{
4995 struct job *jp;
4996 int retval;
4997
4998 retval = 0;
4999 if (job_warning)
5000 goto out;
5001 jp = curjob;
5002 if (jp && jp->state == JOBSTOPPED) {
5003 out2str("You have stopped jobs.\n");
5004 job_warning = 2;
5005 retval++;
5006 }
5007 out:
5008 return retval;
5009}
5010
5011
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005012/* ============ redir.c
5013 *
5014 * Code for dealing with input/output redirection.
5015 */
5016
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005017#undef EMPTY
5018#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005019#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005020#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005021
5022/*
5023 * Open a file in noclobber mode.
5024 * The code was copied from bash.
5025 */
5026static int
5027noclobberopen(const char *fname)
5028{
5029 int r, fd;
5030 struct stat finfo, finfo2;
5031
5032 /*
5033 * If the file exists and is a regular file, return an error
5034 * immediately.
5035 */
5036 r = stat(fname, &finfo);
5037 if (r == 0 && S_ISREG(finfo.st_mode)) {
5038 errno = EEXIST;
5039 return -1;
5040 }
5041
5042 /*
5043 * If the file was not present (r != 0), make sure we open it
5044 * exclusively so that if it is created before we open it, our open
5045 * will fail. Make sure that we do not truncate an existing file.
5046 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5047 * file was not a regular file, we leave O_EXCL off.
5048 */
5049 if (r != 0)
5050 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5051 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5052
5053 /* If the open failed, return the file descriptor right away. */
5054 if (fd < 0)
5055 return fd;
5056
5057 /*
5058 * OK, the open succeeded, but the file may have been changed from a
5059 * non-regular file to a regular file between the stat and the open.
5060 * We are assuming that the O_EXCL open handles the case where FILENAME
5061 * did not exist and is symlinked to an existing file between the stat
5062 * and open.
5063 */
5064
5065 /*
5066 * If we can open it and fstat the file descriptor, and neither check
5067 * revealed that it was a regular file, and the file has not been
5068 * replaced, return the file descriptor.
5069 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005070 if (fstat(fd, &finfo2) == 0
5071 && !S_ISREG(finfo2.st_mode)
5072 && finfo.st_dev == finfo2.st_dev
5073 && finfo.st_ino == finfo2.st_ino
5074 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005075 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005076 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005077
5078 /* The file has been replaced. badness. */
5079 close(fd);
5080 errno = EEXIST;
5081 return -1;
5082}
5083
5084/*
5085 * Handle here documents. Normally we fork off a process to write the
5086 * data to a pipe. If the document is short, we can stuff the data in
5087 * the pipe without forking.
5088 */
5089/* openhere needs this forward reference */
5090static void expandhere(union node *arg, int fd);
5091static int
5092openhere(union node *redir)
5093{
5094 int pip[2];
5095 size_t len = 0;
5096
5097 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005098 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005099 if (redir->type == NHERE) {
5100 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005101 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005102 full_write(pip[1], redir->nhere.doc->narg.text, len);
5103 goto out;
5104 }
5105 }
5106 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005107 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005108 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005109 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5110 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5111 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5112 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005113 signal(SIGPIPE, SIG_DFL);
5114 if (redir->type == NHERE)
5115 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005116 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005117 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005118 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005119 }
5120 out:
5121 close(pip[1]);
5122 return pip[0];
5123}
5124
5125static int
5126openredirect(union node *redir)
5127{
5128 char *fname;
5129 int f;
5130
5131 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005132/* Can't happen, our single caller does this itself */
5133// case NTOFD:
5134// case NFROMFD:
5135// return -1;
5136 case NHERE:
5137 case NXHERE:
5138 return openhere(redir);
5139 }
5140
5141 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5142 * allocated space. Do it only when we know it is safe.
5143 */
5144 fname = redir->nfile.expfname;
5145
5146 switch (redir->nfile.type) {
5147 default:
5148#if DEBUG
5149 abort();
5150#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005151 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005152 f = open(fname, O_RDONLY);
5153 if (f < 0)
5154 goto eopen;
5155 break;
5156 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005157 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005158 if (f < 0)
5159 goto ecreate;
5160 break;
5161 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005162#if ENABLE_ASH_BASH_COMPAT
5163 case NTO2:
5164#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005165 /* Take care of noclobber mode. */
5166 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005167 f = noclobberopen(fname);
5168 if (f < 0)
5169 goto ecreate;
5170 break;
5171 }
5172 /* FALLTHROUGH */
5173 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005174 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5175 if (f < 0)
5176 goto ecreate;
5177 break;
5178 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005179 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5180 if (f < 0)
5181 goto ecreate;
5182 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005183 }
5184
5185 return f;
5186 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005187 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005188 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005189 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005190}
5191
5192/*
5193 * Copy a file descriptor to be >= to. Returns -1
5194 * if the source file descriptor is closed, EMPTY if there are no unused
5195 * file descriptors left.
5196 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005197/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5198 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005199enum {
5200 COPYFD_EXACT = (int)~(INT_MAX),
5201 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5202};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005203static int
5204copyfd(int from, int to)
5205{
5206 int newfd;
5207
Denis Vlasenko5a867312008-07-24 19:46:38 +00005208 if (to & COPYFD_EXACT) {
5209 to &= ~COPYFD_EXACT;
5210 /*if (from != to)*/
5211 newfd = dup2(from, to);
5212 } else {
5213 newfd = fcntl(from, F_DUPFD, to);
5214 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005215 if (newfd < 0) {
5216 if (errno == EMFILE)
5217 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005218 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005219 ash_msg_and_raise_error("%d: %m", from);
5220 }
5221 return newfd;
5222}
5223
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005224/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005225struct two_fd_t {
5226 int orig, copy;
5227};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005228struct redirtab {
5229 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005230 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005231 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005232 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005233};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005234#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005235
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005236static int
5237need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005238{
5239 int i;
5240
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005241 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005242 return 0;
5243
5244 for (i = 0; i < rp->pair_count; i++) {
5245 if (rp->two_fd[i].orig == fd) {
5246 /* already remembered */
5247 return 0;
5248 }
5249 }
5250 return 1;
5251}
5252
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005253/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005254static int
5255is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005256{
5257 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005258 struct parsefile *pf;
5259
5260 if (fd == -1)
5261 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005262 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005263 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005264 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005265 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005266 * $ ash # running ash interactively
5267 * $ . ./script.sh
5268 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005269 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005270 * it's still ok to use it: "read" builtin uses it,
5271 * why should we cripple "exec" builtin?
5272 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005273 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005274 return 1;
5275 }
5276 pf = pf->prev;
5277 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005278
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005279 if (!rp)
5280 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005281 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005282 fd |= COPYFD_RESTORE;
5283 for (i = 0; i < rp->pair_count; i++) {
5284 if (rp->two_fd[i].copy == fd) {
5285 return 1;
5286 }
5287 }
5288 return 0;
5289}
5290
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005291/*
5292 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5293 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005294 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005295 */
5296/* flags passed to redirect */
5297#define REDIR_PUSH 01 /* save previous values of file descriptors */
5298#define REDIR_SAVEFD2 03 /* set preverrout */
5299static void
5300redirect(union node *redir, int flags)
5301{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005302 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005303 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005304 int i;
5305 int fd;
5306 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005307 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005308
Denis Vlasenko01631112007-12-16 17:20:38 +00005309 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005310 if (!redir) {
5311 return;
5312 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005313
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005314 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005315 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005316 INT_OFF;
5317 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005318 union node *tmp = redir;
5319 do {
5320 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005321#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005322 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005323 sv_pos++;
5324#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005325 tmp = tmp->nfile.next;
5326 } while (tmp);
5327 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005328 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005329 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005330 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005331 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005332 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005333 while (sv_pos > 0) {
5334 sv_pos--;
5335 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5336 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005337 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005338
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005339 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005340 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005341 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005342 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005343 right_fd = redir->ndup.dupfd;
5344 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005345 /* redirect from/to same file descriptor? */
5346 if (right_fd == fd)
5347 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005348 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005349 if (is_hidden_fd(sv, right_fd)) {
5350 errno = EBADF; /* as if it is closed */
5351 ash_msg_and_raise_error("%d: %m", right_fd);
5352 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005353 newfd = -1;
5354 } else {
5355 newfd = openredirect(redir); /* always >= 0 */
5356 if (fd == newfd) {
5357 /* Descriptor wasn't open before redirect.
5358 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005359 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005360 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005361 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005362 continue;
5363 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005364 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005365#if ENABLE_ASH_BASH_COMPAT
5366 redirect_more:
5367#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005368 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005369 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005370 /* Careful to not accidentally "save"
5371 * to the same fd as right side fd in N>&M */
5372 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5373 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005374/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5375 * are closed in popredir() in the child, preventing them from leaking
5376 * into child. (popredir() also cleans up the mess in case of failures)
5377 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005378 if (i == -1) {
5379 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005380 if (i != EBADF) {
5381 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005382 if (newfd >= 0)
5383 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005384 errno = i;
5385 ash_msg_and_raise_error("%d: %m", fd);
5386 /* NOTREACHED */
5387 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005388 /* EBADF: it is not open - good, remember to close it */
5389 remember_to_close:
5390 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005391 } else { /* fd is open, save its copy */
5392 /* "exec fd>&-" should not close fds
5393 * which point to script file(s).
5394 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005395 if (is_hidden_fd(sv, fd))
5396 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005397 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005398 if (fd == 2)
5399 copied_fd2 = i;
5400 sv->two_fd[sv_pos].orig = fd;
5401 sv->two_fd[sv_pos].copy = i;
5402 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005403 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005404 if (newfd < 0) {
5405 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005406 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005407 /* Don't want to trigger debugging */
5408 if (fd != -1)
5409 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005410 } else {
5411 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005412 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005413 } else if (fd != newfd) { /* move newfd to fd */
5414 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005415#if ENABLE_ASH_BASH_COMPAT
5416 if (!(redir->nfile.type == NTO2 && fd == 2))
5417#endif
5418 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005419 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005420#if ENABLE_ASH_BASH_COMPAT
5421 if (redir->nfile.type == NTO2 && fd == 1) {
5422 /* We already redirected it to fd 1, now copy it to 2 */
5423 newfd = 1;
5424 fd = 2;
5425 goto redirect_more;
5426 }
5427#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005428 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005429
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005430 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005431 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5432 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005433}
5434
5435/*
5436 * Undo the effects of the last redirection.
5437 */
5438static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005439popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005440{
5441 struct redirtab *rp;
5442 int i;
5443
Ron Yorston95650a82015-10-30 19:07:37 +00005444 if (--g_nullredirs >= 0 || redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005445 return;
5446 INT_OFF;
5447 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005448 for (i = 0; i < rp->pair_count; i++) {
5449 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005450 int copy = rp->two_fd[i].copy;
5451 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005452 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005453 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005454 continue;
5455 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005456 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005457 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005458 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005459 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005460 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005461 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005462 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005463 }
5464 }
5465 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005466 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005467 free(rp);
5468 INT_ON;
5469}
5470
5471/*
5472 * Undo all redirections. Called on error or interrupt.
5473 */
5474
5475/*
5476 * Discard all saved file descriptors.
5477 */
5478static void
5479clearredir(int drop)
5480{
5481 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005482 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005483 if (!redirlist)
5484 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005485 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005486 }
5487}
5488
5489static int
5490redirectsafe(union node *redir, int flags)
5491{
5492 int err;
5493 volatile int saveint;
5494 struct jmploc *volatile savehandler = exception_handler;
5495 struct jmploc jmploc;
5496
5497 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005498 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5499 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005500 if (!err) {
5501 exception_handler = &jmploc;
5502 redirect(redir, flags);
5503 }
5504 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005505 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005506 longjmp(exception_handler->loc, 1);
5507 RESTORE_INT(saveint);
5508 return err;
5509}
5510
5511
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005512/* ============ Routines to expand arguments to commands
5513 *
5514 * We have to deal with backquotes, shell variables, and file metacharacters.
5515 */
5516
Mike Frysinger98c52642009-04-02 10:02:37 +00005517#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005518static arith_t
5519ash_arith(const char *s)
5520{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005521 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005522 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005523
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005524 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005525 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005526 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005527
5528 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005529 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005530 if (math_state.errmsg)
5531 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005532 INT_ON;
5533
5534 return result;
5535}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005536#endif
5537
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005538/*
5539 * expandarg flags
5540 */
5541#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5542#define EXP_TILDE 0x2 /* do normal tilde expansion */
5543#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5544#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005545/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5546 * POSIX says for this case:
5547 * Pathname expansion shall not be performed on the word by a
5548 * non-interactive shell; an interactive shell may perform it, but shall
5549 * do so only when the expansion would result in one word.
5550 * Currently, our code complies to the above rule by never globbing
5551 * redirection filenames.
5552 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5553 * (this means that on a typical Linux distro, bash almost always
5554 * performs globbing, and thus diverges from what we do).
5555 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005556#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005557#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005558#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5559#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005560#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005561/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005562 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005563 */
5564#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5565#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005566#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5567#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005568#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005569
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005570/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005571#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005572/* Do not skip NUL characters. */
5573#define QUOTES_KEEPNUL EXP_TILDE
5574
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005575/*
5576 * Structure specifying which parts of the string should be searched
5577 * for IFS characters.
5578 */
5579struct ifsregion {
5580 struct ifsregion *next; /* next region in list */
5581 int begoff; /* offset of start of region */
5582 int endoff; /* offset of end of region */
5583 int nulonly; /* search for nul bytes only */
5584};
5585
5586struct arglist {
5587 struct strlist *list;
5588 struct strlist **lastp;
5589};
5590
5591/* output of current string */
5592static char *expdest;
5593/* list of back quote expressions */
5594static struct nodelist *argbackq;
5595/* first struct in list of ifs regions */
5596static struct ifsregion ifsfirst;
5597/* last struct in list */
5598static struct ifsregion *ifslastp;
5599/* holds expanded arg list */
5600static struct arglist exparg;
5601
5602/*
5603 * Our own itoa().
5604 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005605#if !ENABLE_SH_MATH_SUPPORT
5606/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5607typedef long arith_t;
5608# define ARITH_FMT "%ld"
5609#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005610static int
5611cvtnum(arith_t num)
5612{
5613 int len;
5614
Denys Vlasenko9c541002015-10-07 15:44:36 +02005615 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5616 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005617 STADJUST(len, expdest);
5618 return len;
5619}
5620
5621static size_t
5622esclen(const char *start, const char *p)
5623{
5624 size_t esc = 0;
5625
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005626 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005627 esc++;
5628 }
5629 return esc;
5630}
5631
5632/*
5633 * Remove any CTLESC characters from a string.
5634 */
5635static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005636rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005637{
Ron Yorston417622c2015-05-18 09:59:14 +02005638 static const char qchars[] ALIGN1 = {
5639 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005640
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005641 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005642 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005643 unsigned protect_against_glob;
5644 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005645 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005646
Ron Yorston417622c2015-05-18 09:59:14 +02005647 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005648 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005649 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005650
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005651 q = p;
5652 r = str;
5653 if (flag & RMESCAPE_ALLOC) {
5654 size_t len = p - str;
5655 size_t fulllen = len + strlen(p) + 1;
5656
5657 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005658 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005659 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005660 /* p and str may be invalidated by makestrspace */
5661 str = (char *)stackblock() + strloc;
5662 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005663 } else if (flag & RMESCAPE_HEAP) {
5664 r = ckmalloc(fulllen);
5665 } else {
5666 r = stalloc(fulllen);
5667 }
5668 q = r;
5669 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005670 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005671 }
5672 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005673
Ron Yorston549deab2015-05-18 09:57:51 +02005674 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005675 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005676 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005677 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005678 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005679// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005680 inquotes = ~inquotes;
5681 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005682 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005683 continue;
5684 }
Ron Yorston549deab2015-05-18 09:57:51 +02005685 if ((unsigned char)*p == CTLESC) {
5686 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005687#if DEBUG
5688 if (*p == '\0')
5689 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5690#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005691 if (protect_against_glob) {
5692 *q++ = '\\';
5693 }
5694 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005695 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005696 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005697 goto copy;
5698 }
Ron Yorston417622c2015-05-18 09:59:14 +02005699#if ENABLE_ASH_BASH_COMPAT
5700 else if (*p == '/' && slash) {
5701 /* stop handling globbing and mark location of slash */
5702 globbing = slash = 0;
5703 *p = CTLESC;
5704 }
5705#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005706 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005707 copy:
5708 *q++ = *p++;
5709 }
5710 *q = '\0';
5711 if (flag & RMESCAPE_GROW) {
5712 expdest = r;
5713 STADJUST(q - r + 1, expdest);
5714 }
5715 return r;
5716}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005717#define pmatch(a, b) !fnmatch((a), (b), 0)
5718
5719/*
5720 * Prepare a pattern for a expmeta (internal glob(3)) call.
5721 *
5722 * Returns an stalloced string.
5723 */
5724static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005725preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005726{
Ron Yorston549deab2015-05-18 09:57:51 +02005727 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005728}
5729
5730/*
5731 * Put a string on the stack.
5732 */
5733static void
5734memtodest(const char *p, size_t len, int syntax, int quotes)
5735{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005736 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005737
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005738 if (!len)
5739 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005740
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005741 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5742
5743 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005744 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005745 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005746 int n = SIT(c, syntax);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005747 if ((quotes & QUOTES_ESC)
5748 && ((n == CCTL)
5749 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5750 && n == CBACK)
5751 )
5752 ) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005753 USTPUTC(CTLESC, q);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005754 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005755 } else if (!(quotes & QUOTES_KEEPNUL))
5756 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005757 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005758 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005759
5760 expdest = q;
5761}
5762
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005763static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005764strtodest(const char *p, int syntax, int quotes)
5765{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005766 size_t len = strlen(p);
5767 memtodest(p, len, syntax, quotes);
5768 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005769}
5770
5771/*
5772 * Record the fact that we have to scan this region of the
5773 * string for IFS characters.
5774 */
5775static void
5776recordregion(int start, int end, int nulonly)
5777{
5778 struct ifsregion *ifsp;
5779
5780 if (ifslastp == NULL) {
5781 ifsp = &ifsfirst;
5782 } else {
5783 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005784 ifsp = ckzalloc(sizeof(*ifsp));
5785 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005786 ifslastp->next = ifsp;
5787 INT_ON;
5788 }
5789 ifslastp = ifsp;
5790 ifslastp->begoff = start;
5791 ifslastp->endoff = end;
5792 ifslastp->nulonly = nulonly;
5793}
5794
5795static void
5796removerecordregions(int endoff)
5797{
5798 if (ifslastp == NULL)
5799 return;
5800
5801 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005802 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005803 struct ifsregion *ifsp;
5804 INT_OFF;
5805 ifsp = ifsfirst.next->next;
5806 free(ifsfirst.next);
5807 ifsfirst.next = ifsp;
5808 INT_ON;
5809 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005810 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005811 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005812 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005813 ifslastp = &ifsfirst;
5814 ifsfirst.endoff = endoff;
5815 }
5816 return;
5817 }
5818
5819 ifslastp = &ifsfirst;
5820 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005821 ifslastp = ifslastp->next;
5822 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005823 struct ifsregion *ifsp;
5824 INT_OFF;
5825 ifsp = ifslastp->next->next;
5826 free(ifslastp->next);
5827 ifslastp->next = ifsp;
5828 INT_ON;
5829 }
5830 if (ifslastp->endoff > endoff)
5831 ifslastp->endoff = endoff;
5832}
5833
5834static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005835exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005836{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005837 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005838 char *name;
5839 struct passwd *pw;
5840 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005841 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005842
5843 name = p + 1;
5844
5845 while ((c = *++p) != '\0') {
5846 switch (c) {
5847 case CTLESC:
5848 return startp;
5849 case CTLQUOTEMARK:
5850 return startp;
5851 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005852 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005853 goto done;
5854 break;
5855 case '/':
5856 case CTLENDVAR:
5857 goto done;
5858 }
5859 }
5860 done:
5861 *p = '\0';
5862 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005863 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005864 } else {
5865 pw = getpwnam(name);
5866 if (pw == NULL)
5867 goto lose;
5868 home = pw->pw_dir;
5869 }
5870 if (!home || !*home)
5871 goto lose;
5872 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005873 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005874 return p;
5875 lose:
5876 *p = c;
5877 return startp;
5878}
5879
5880/*
5881 * Execute a command inside back quotes. If it's a builtin command, we
5882 * want to save its output in a block obtained from malloc. Otherwise
5883 * we fork off a subprocess and get the output of the command via a pipe.
5884 * Should be called with interrupts off.
5885 */
5886struct backcmd { /* result of evalbackcmd */
5887 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005888 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005889 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005890 struct job *jp; /* job structure for command */
5891};
5892
5893/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005894#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02005895static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005896
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005897static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005898evalbackcmd(union node *n, struct backcmd *result)
5899{
5900 int saveherefd;
5901
5902 result->fd = -1;
5903 result->buf = NULL;
5904 result->nleft = 0;
5905 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005906 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005907 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005908
5909 saveherefd = herefd;
5910 herefd = -1;
5911
5912 {
5913 int pip[2];
5914 struct job *jp;
5915
5916 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005917 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005918 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005919 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5920 FORCE_INT_ON;
5921 close(pip[0]);
5922 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005923 /*close(1);*/
5924 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005925 close(pip[1]);
5926 }
5927 eflag = 0;
5928 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5929 /* NOTREACHED */
5930 }
5931 close(pip[1]);
5932 result->fd = pip[0];
5933 result->jp = jp;
5934 }
5935 herefd = saveherefd;
5936 out:
5937 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5938 result->fd, result->buf, result->nleft, result->jp));
5939}
5940
5941/*
5942 * Expand stuff in backwards quotes.
5943 */
5944static void
Ron Yorston549deab2015-05-18 09:57:51 +02005945expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005946{
5947 struct backcmd in;
5948 int i;
5949 char buf[128];
5950 char *p;
5951 char *dest;
5952 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02005953 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005954 struct stackmark smark;
5955
5956 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02005957 startloc = expdest - (char *)stackblock();
5958 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005959 evalbackcmd(cmd, &in);
5960 popstackmark(&smark);
5961
5962 p = in.buf;
5963 i = in.nleft;
5964 if (i == 0)
5965 goto read;
5966 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02005967 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005968 read:
5969 if (in.fd < 0)
5970 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01005971 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005972 TRACE(("expbackq: read returns %d\n", i));
5973 if (i <= 0)
5974 break;
5975 p = buf;
5976 }
5977
Denis Vlasenko60818682007-09-28 22:07:23 +00005978 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005979 if (in.fd >= 0) {
5980 close(in.fd);
5981 back_exitstatus = waitforjob(in.jp);
5982 }
5983 INT_ON;
5984
5985 /* Eat all trailing newlines */
5986 dest = expdest;
5987 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5988 STUNPUTC(dest);
5989 expdest = dest;
5990
Ron Yorston549deab2015-05-18 09:57:51 +02005991 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005992 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005993 TRACE(("evalbackq: size:%d:'%.*s'\n",
5994 (int)((dest - (char *)stackblock()) - startloc),
5995 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005996 stackblock() + startloc));
5997}
5998
Mike Frysinger98c52642009-04-02 10:02:37 +00005999#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000/*
6001 * Expand arithmetic expression. Backup to start of expression,
6002 * evaluate, place result in (backed up) result, adjust string position.
6003 */
6004static void
Ron Yorston549deab2015-05-18 09:57:51 +02006005expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006006{
6007 char *p, *start;
6008 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006009 int len;
6010
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006011 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006012
6013 /*
6014 * This routine is slightly over-complicated for
6015 * efficiency. Next we scan backwards looking for the
6016 * start of arithmetic.
6017 */
6018 start = stackblock();
6019 p = expdest - 1;
6020 *p = '\0';
6021 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006022 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006023 int esc;
6024
Denys Vlasenkocd716832009-11-28 22:14:02 +01006025 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006026 p--;
6027#if DEBUG
6028 if (p < start) {
6029 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6030 }
6031#endif
6032 }
6033
6034 esc = esclen(start, p);
6035 if (!(esc % 2)) {
6036 break;
6037 }
6038
6039 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006040 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006041
6042 begoff = p - start;
6043
6044 removerecordregions(begoff);
6045
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006046 expdest = p;
6047
Ron Yorston549deab2015-05-18 09:57:51 +02006048 if (flag & QUOTES_ESC)
6049 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006050
Ron Yorston549deab2015-05-18 09:57:51 +02006051 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006052
Ron Yorston549deab2015-05-18 09:57:51 +02006053 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006054 recordregion(begoff, begoff + len, 0);
6055}
6056#endif
6057
6058/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006059static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006060
6061/*
6062 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6063 * characters to allow for further processing. Otherwise treat
6064 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006065 *
6066 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6067 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6068 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069 */
6070static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006071argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006072{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006073 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006074 '=',
6075 ':',
6076 CTLQUOTEMARK,
6077 CTLENDVAR,
6078 CTLESC,
6079 CTLVAR,
6080 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006081#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006082 CTLENDARI,
6083#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006084 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006085 };
6086 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006087 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006088 int inquotes;
6089 size_t length;
6090 int startloc;
6091
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006092 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006093 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006094 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006095 reject++;
6096 }
6097 inquotes = 0;
6098 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006099 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006100 char *q;
6101
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006102 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006103 tilde:
6104 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006105 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006106 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006107 }
6108 start:
6109 startloc = expdest - (char *)stackblock();
6110 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006111 unsigned char c;
6112
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006113 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006114 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006115 if (c) {
6116 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006117 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006118 ) {
6119 /* c == '=' || c == ':' || c == CTLENDARI */
6120 length++;
6121 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006122 }
6123 if (length > 0) {
6124 int newloc;
6125 expdest = stack_nputstr(p, length, expdest);
6126 newloc = expdest - (char *)stackblock();
6127 if (breakall && !inquotes && newloc > startloc) {
6128 recordregion(startloc, newloc, 0);
6129 }
6130 startloc = newloc;
6131 }
6132 p += length + 1;
6133 length = 0;
6134
6135 switch (c) {
6136 case '\0':
6137 goto breakloop;
6138 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006139 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006140 p--;
6141 continue;
6142 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006143 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006144 reject++;
6145 /* fall through */
6146 case ':':
6147 /*
6148 * sort of a hack - expand tildes in variable
6149 * assignments (after the first '=' and after ':'s).
6150 */
6151 if (*--p == '~') {
6152 goto tilde;
6153 }
6154 continue;
6155 }
6156
6157 switch (c) {
6158 case CTLENDVAR: /* ??? */
6159 goto breakloop;
6160 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006161 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006162 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006163 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6164 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006165 goto start;
6166 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006167 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006168 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006169 p--;
6170 length++;
6171 startloc++;
6172 }
6173 break;
6174 case CTLESC:
6175 startloc++;
6176 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006177
6178 /*
6179 * Quoted parameter expansion pattern: remove quote
6180 * unless inside inner quotes or we have a literal
6181 * backslash.
6182 */
6183 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6184 EXP_QPAT && *p != '\\')
6185 break;
6186
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006187 goto addquote;
6188 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006189 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006190 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006191 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006192 goto start;
6193 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006194 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006195 argbackq = argbackq->next;
6196 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006197#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006198 case CTLENDARI:
6199 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006200 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006201 goto start;
6202#endif
6203 }
6204 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006205 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006206}
6207
6208static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006209scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6210 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006211{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006212 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006213 char c;
6214
6215 loc = startp;
6216 loc2 = rmesc;
6217 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006218 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006219 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006220
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006221 c = *loc2;
6222 if (zero) {
6223 *loc2 = '\0';
6224 s = rmesc;
6225 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006226 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006227
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006228 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006229 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006230 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006231 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006232 loc++;
6233 loc++;
6234 loc2++;
6235 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006236 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006237}
6238
6239static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006240scanright(char *startp, char *rmesc, char *rmescend,
6241 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006242{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006243#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6244 int try2optimize = match_at_start;
6245#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006246 int esc = 0;
6247 char *loc;
6248 char *loc2;
6249
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006250 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6251 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6252 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6253 * Logic:
6254 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6255 * and on each iteration they go back two/one char until they reach the beginning.
6256 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6257 */
6258 /* TODO: document in what other circumstances we are called. */
6259
6260 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006261 int match;
6262 char c = *loc2;
6263 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006264 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265 *loc2 = '\0';
6266 s = rmesc;
6267 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006268 match = pmatch(pattern, s);
6269 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270 *loc2 = c;
6271 if (match)
6272 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006273#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6274 if (try2optimize) {
6275 /* Maybe we can optimize this:
6276 * if pattern ends with unescaped *, we can avoid checking
6277 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6278 * it wont match truncated "raw_value_of_" strings too.
6279 */
6280 unsigned plen = strlen(pattern);
6281 /* Does it end with "*"? */
6282 if (plen != 0 && pattern[--plen] == '*') {
6283 /* "xxxx*" is not escaped */
6284 /* "xxx\*" is escaped */
6285 /* "xx\\*" is not escaped */
6286 /* "x\\\*" is escaped */
6287 int slashes = 0;
6288 while (plen != 0 && pattern[--plen] == '\\')
6289 slashes++;
6290 if (!(slashes & 1))
6291 break; /* ends with unescaped "*" */
6292 }
6293 try2optimize = 0;
6294 }
6295#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006296 loc--;
6297 if (quotes) {
6298 if (--esc < 0) {
6299 esc = esclen(startp, loc);
6300 }
6301 if (esc % 2) {
6302 esc--;
6303 loc--;
6304 }
6305 }
6306 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006307 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006308}
6309
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006310static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006311static void
6312varunset(const char *end, const char *var, const char *umsg, int varflags)
6313{
6314 const char *msg;
6315 const char *tail;
6316
6317 tail = nullstr;
6318 msg = "parameter not set";
6319 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006320 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006321 if (varflags & VSNUL)
6322 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006323 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006324 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006325 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006326 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006327 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006328}
6329
6330static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006331subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006332 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006333{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006334 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006335 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006336 char *startp;
6337 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006338 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006339 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006340 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006341 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006342 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006343 int amount, resetloc;
6344 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006345 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006346 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006347
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006348 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6349 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006350
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006351 herefd = -1;
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006352 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006353 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6354 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006355 STPUTC('\0', expdest);
6356 herefd = saveherefd;
6357 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006358 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006359
6360 switch (subtype) {
6361 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006362 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006363 amount = startp - expdest;
6364 STADJUST(amount, expdest);
6365 return startp;
6366
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006367 case VSQUESTION:
6368 varunset(p, varname, startp, varflags);
6369 /* NOTREACHED */
6370
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006371#if ENABLE_ASH_BASH_COMPAT
6372 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006373//TODO: support more general format ${v:EXPR:EXPR},
6374// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006375 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006376 /* Read POS in ${var:POS:LEN} */
6377 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006378 len = str - startp - 1;
6379
6380 /* *loc != '\0', guaranteed by parser */
6381 if (quotes) {
6382 char *ptr;
6383
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006384 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006385 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006386 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006387 len--;
6388 ptr++;
6389 }
6390 }
6391 }
6392 orig_len = len;
6393
6394 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006395 /* ${var::LEN} */
6396 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006397 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006398 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006399 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006400 while (*loc && *loc != ':') {
6401 /* TODO?
6402 * bash complains on: var=qwe; echo ${var:1a:123}
6403 if (!isdigit(*loc))
6404 ash_msg_and_raise_error(msg_illnum, str);
6405 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006406 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006407 }
6408 if (*loc++ == ':') {
6409 len = number(loc);
6410 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006411 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006412 if (pos < 0) {
6413 /* ${VAR:$((-n)):l} starts n chars from the end */
6414 pos = orig_len + pos;
6415 }
6416 if ((unsigned)pos >= orig_len) {
6417 /* apart from obvious ${VAR:999999:l},
6418 * covers ${VAR:$((-9999999)):l} - result is ""
6419 * (bash-compat)
6420 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006421 pos = 0;
6422 len = 0;
6423 }
6424 if (len > (orig_len - pos))
6425 len = orig_len - pos;
6426
6427 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006428 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006429 str++;
6430 }
6431 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006432 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006433 *loc++ = *str++;
6434 *loc++ = *str++;
6435 }
6436 *loc = '\0';
6437 amount = loc - expdest;
6438 STADJUST(amount, expdest);
6439 return loc;
6440#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006441 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006442
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006443 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006444
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006445 /* We'll comeback here if we grow the stack while handling
6446 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6447 * stack will need rebasing, and we'll need to remove our work
6448 * areas each time
6449 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006450 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006451
6452 amount = expdest - ((char *)stackblock() + resetloc);
6453 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006454 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006455
6456 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006457 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006458 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006459 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006460 if (rmesc != startp) {
6461 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006462 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006463 }
6464 }
6465 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006466 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006467 /*
6468 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6469 * The result is a_\_z_c (not a\_\_z_c)!
6470 *
6471 * The search pattern and replace string treat backslashes differently!
6472 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6473 * and string. It's only used on the first call.
6474 */
6475 preglob(str, IF_ASH_BASH_COMPAT(
6476 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6477 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006478
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006479#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006480 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006481 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006482 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006483
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006484 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006485 repl = strchr(str, CTLESC);
6486 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006487 *repl++ = '\0';
6488 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006489 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006490 }
Ron Yorston417622c2015-05-18 09:59:14 +02006491 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006492
6493 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006494 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006495 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006496
6497 len = 0;
6498 idx = startp;
6499 end = str - 1;
6500 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006501 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006502 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006503 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006504 if (!loc) {
6505 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006506 char *restart_detect = stackblock();
6507 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006508 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006509 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006510 idx++;
6511 len++;
6512 STPUTC(*idx, expdest);
6513 }
6514 if (stackblock() != restart_detect)
6515 goto restart;
6516 idx++;
6517 len++;
6518 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006519 /* continue; - prone to quadratic behavior, smarter code: */
6520 if (idx >= end)
6521 break;
6522 if (str[0] == '*') {
6523 /* Pattern is "*foo". If "*foo" does not match "long_string",
6524 * it would never match "ong_string" etc, no point in trying.
6525 */
6526 goto skip_matching;
6527 }
6528 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006529 }
6530
6531 if (subtype == VSREPLACEALL) {
6532 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006533 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006534 idx++;
6535 idx++;
6536 rmesc++;
6537 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006538 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006539 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006540 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006541
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006542 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006543 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006544 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006545 if (quotes && *loc == '\\') {
6546 STPUTC(CTLESC, expdest);
6547 len++;
6548 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006549 STPUTC(*loc, expdest);
6550 if (stackblock() != restart_detect)
6551 goto restart;
6552 len++;
6553 }
6554
6555 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006556 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006557 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006558 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006559 STPUTC(*idx, expdest);
6560 if (stackblock() != restart_detect)
6561 goto restart;
6562 len++;
6563 idx++;
6564 }
6565 break;
6566 }
6567 }
6568
6569 /* We've put the replaced text into a buffer at workloc, now
6570 * move it to the right place and adjust the stack.
6571 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006572 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006573 startp = (char *)stackblock() + startloc;
6574 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006575 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006576 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006577 STADJUST(-amount, expdest);
6578 return startp;
6579 }
6580#endif /* ENABLE_ASH_BASH_COMPAT */
6581
6582 subtype -= VSTRIMRIGHT;
6583#if DEBUG
6584 if (subtype < 0 || subtype > 7)
6585 abort();
6586#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006587 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006588 zero = subtype >> 1;
6589 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6590 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6591
6592 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6593 if (loc) {
6594 if (zero) {
6595 memmove(startp, loc, str - loc);
6596 loc = startp + (str - loc) - 1;
6597 }
6598 *loc = '\0';
6599 amount = loc - expdest;
6600 STADJUST(amount, expdest);
6601 }
6602 return loc;
6603}
6604
6605/*
6606 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006607 * name parameter (examples):
6608 * ash -c 'echo $1' name:'1='
6609 * ash -c 'echo $qwe' name:'qwe='
6610 * ash -c 'echo $$' name:'$='
6611 * ash -c 'echo ${$}' name:'$='
6612 * ash -c 'echo ${$##q}' name:'$=q'
6613 * ash -c 'echo ${#$}' name:'$='
6614 * note: examples with bad shell syntax:
6615 * ash -c 'echo ${#$1}' name:'$=1'
6616 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006617 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006618static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006619varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006620{
Mike Frysinger98c52642009-04-02 10:02:37 +00006621 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006622 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006623 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006624 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006625 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006626 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006627 int subtype = varflags & VSTYPE;
6628 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6629 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006630 int syntax;
6631
6632 sep = (flags & EXP_FULL) << CHAR_BIT;
6633 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006634
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006635 switch (*name) {
6636 case '$':
6637 num = rootpid;
6638 goto numvar;
6639 case '?':
6640 num = exitstatus;
6641 goto numvar;
6642 case '#':
6643 num = shellparam.nparam;
6644 goto numvar;
6645 case '!':
6646 num = backgndpid;
6647 if (num == 0)
6648 return -1;
6649 numvar:
6650 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006651 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006652 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006653 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006654 for (i = NOPTS - 1; i >= 0; i--) {
6655 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006656 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006657 len++;
6658 }
6659 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006660 check_1char_name:
6661#if 0
6662 /* handles cases similar to ${#$1} */
6663 if (name[2] != '\0')
6664 raise_error_syntax("bad substitution");
6665#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006666 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006667 case '@':
6668 if (quoted && sep)
6669 goto param;
6670 /* fall through */
6671 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006672 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006673 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006674
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006675 if (quoted)
6676 sep = 0;
6677 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006678 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006679 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006680 *quotedp = !sepc;
6681 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006682 if (!ap)
6683 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006684 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006685 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006686
6687 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006688 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006689 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006690 }
6691 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006692 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006693 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006694 case '0':
6695 case '1':
6696 case '2':
6697 case '3':
6698 case '4':
6699 case '5':
6700 case '6':
6701 case '7':
6702 case '8':
6703 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006704 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006705 if (num < 0 || num > shellparam.nparam)
6706 return -1;
6707 p = num ? shellparam.p[num - 1] : arg0;
6708 goto value;
6709 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006710 /* NB: name has form "VAR=..." */
6711
6712 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6713 * which should be considered before we check variables. */
6714 if (var_str_list) {
6715 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6716 p = NULL;
6717 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006718 char *str, *eq;
6719 str = var_str_list->text;
6720 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006721 if (!eq) /* stop at first non-assignment */
6722 break;
6723 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006724 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006725 && strncmp(str, name, name_len) == 0
6726 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006727 p = eq;
6728 /* goto value; - WRONG! */
6729 /* think "A=1 A=2 B=$A" */
6730 }
6731 var_str_list = var_str_list->next;
6732 } while (var_str_list);
6733 if (p)
6734 goto value;
6735 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006736 p = lookupvar(name);
6737 value:
6738 if (!p)
6739 return -1;
6740
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006741 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006742#if ENABLE_UNICODE_SUPPORT
6743 if (subtype == VSLENGTH && len > 0) {
6744 reinit_unicode_for_ash();
6745 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006746 STADJUST(-len, expdest);
6747 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006748 len = unicode_strlen(p);
6749 }
6750 }
6751#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006752 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006753 }
6754
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006755 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006756 STADJUST(-len, expdest);
6757 return len;
6758}
6759
6760/*
6761 * Expand a variable, and return a pointer to the next character in the
6762 * input string.
6763 */
6764static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006765evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006766{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006767 char varflags;
6768 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006769 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006770 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006771 char *var;
6772 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006773 int startloc;
6774 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006775
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006776 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006777 subtype = varflags & VSTYPE;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006778 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006779 var = p;
6780 easy = (!quoted || (*var == '@' && shellparam.nparam));
6781 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006782 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006783
6784 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006785 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006786 if (varflags & VSNUL)
6787 varlen--;
6788
6789 if (subtype == VSPLUS) {
6790 varlen = -1 - varlen;
6791 goto vsplus;
6792 }
6793
6794 if (subtype == VSMINUS) {
6795 vsplus:
6796 if (varlen < 0) {
6797 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006798 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006799 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006800 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006801 );
6802 goto end;
6803 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006804 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006805 }
6806
6807 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006808 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006809 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006810
6811 subevalvar(p, var, 0, subtype, startloc, varflags,
6812 flag & ~QUOTES_ESC, var_str_list);
6813 varflags &= ~VSNUL;
6814 /*
6815 * Remove any recorded regions beyond
6816 * start of variable
6817 */
6818 removerecordregions(startloc);
6819 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006820 }
6821
6822 if (varlen < 0 && uflag)
6823 varunset(p, var, 0, 0);
6824
6825 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006826 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006827 goto record;
6828 }
6829
6830 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006831 record:
6832 if (!easy)
6833 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006834 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006835 goto end;
6836 }
6837
6838#if DEBUG
6839 switch (subtype) {
6840 case VSTRIMLEFT:
6841 case VSTRIMLEFTMAX:
6842 case VSTRIMRIGHT:
6843 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006844#if ENABLE_ASH_BASH_COMPAT
6845 case VSSUBSTR:
6846 case VSREPLACE:
6847 case VSREPLACEALL:
6848#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006849 break;
6850 default:
6851 abort();
6852 }
6853#endif
6854
6855 if (varlen >= 0) {
6856 /*
6857 * Terminate the string and start recording the pattern
6858 * right after it
6859 */
6860 STPUTC('\0', expdest);
6861 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006862 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006863 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006864 int amount = expdest - (
6865 (char *)stackblock() + patloc - 1
6866 );
6867 STADJUST(-amount, expdest);
6868 }
6869 /* Remove any recorded regions beyond start of variable */
6870 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006871 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006872 }
6873
6874 end:
6875 if (subtype != VSNORMAL) { /* skip to end of alternative */
6876 int nesting = 1;
6877 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006878 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006879 if (c == CTLESC)
6880 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006881 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006882 if (varlen >= 0)
6883 argbackq = argbackq->next;
6884 } else if (c == CTLVAR) {
6885 if ((*p++ & VSTYPE) != VSNORMAL)
6886 nesting++;
6887 } else if (c == CTLENDVAR) {
6888 if (--nesting == 0)
6889 break;
6890 }
6891 }
6892 }
6893 return p;
6894}
6895
6896/*
6897 * Break the argument string into pieces based upon IFS and add the
6898 * strings to the argument list. The regions of the string to be
6899 * searched for IFS characters have been stored by recordregion.
6900 */
6901static void
6902ifsbreakup(char *string, struct arglist *arglist)
6903{
6904 struct ifsregion *ifsp;
6905 struct strlist *sp;
6906 char *start;
6907 char *p;
6908 char *q;
6909 const char *ifs, *realifs;
6910 int ifsspc;
6911 int nulonly;
6912
6913 start = string;
6914 if (ifslastp != NULL) {
6915 ifsspc = 0;
6916 nulonly = 0;
6917 realifs = ifsset() ? ifsval() : defifs;
6918 ifsp = &ifsfirst;
6919 do {
6920 p = string + ifsp->begoff;
6921 nulonly = ifsp->nulonly;
6922 ifs = nulonly ? nullstr : realifs;
6923 ifsspc = 0;
6924 while (p < string + ifsp->endoff) {
6925 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006926 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006927 p++;
6928 if (!strchr(ifs, *p)) {
6929 p++;
6930 continue;
6931 }
6932 if (!nulonly)
6933 ifsspc = (strchr(defifs, *p) != NULL);
6934 /* Ignore IFS whitespace at start */
6935 if (q == start && ifsspc) {
6936 p++;
6937 start = p;
6938 continue;
6939 }
6940 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006941 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006942 sp->text = start;
6943 *arglist->lastp = sp;
6944 arglist->lastp = &sp->next;
6945 p++;
6946 if (!nulonly) {
6947 for (;;) {
6948 if (p >= string + ifsp->endoff) {
6949 break;
6950 }
6951 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006952 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006953 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006954 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006955 p = q;
6956 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006957 }
6958 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006959 if (ifsspc) {
6960 p++;
6961 ifsspc = 0;
6962 } else {
6963 p = q;
6964 break;
6965 }
6966 } else
6967 p++;
6968 }
6969 }
6970 start = p;
6971 } /* while */
6972 ifsp = ifsp->next;
6973 } while (ifsp != NULL);
6974 if (nulonly)
6975 goto add;
6976 }
6977
6978 if (!*start)
6979 return;
6980
6981 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006982 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006983 sp->text = start;
6984 *arglist->lastp = sp;
6985 arglist->lastp = &sp->next;
6986}
6987
6988static void
6989ifsfree(void)
6990{
6991 struct ifsregion *p;
6992
6993 INT_OFF;
6994 p = ifsfirst.next;
6995 do {
6996 struct ifsregion *ifsp;
6997 ifsp = p->next;
6998 free(p);
6999 p = ifsp;
7000 } while (p);
7001 ifslastp = NULL;
7002 ifsfirst.next = NULL;
7003 INT_ON;
7004}
7005
7006/*
7007 * Add a file name to the list.
7008 */
7009static void
7010addfname(const char *name)
7011{
7012 struct strlist *sp;
7013
Denis Vlasenko597906c2008-02-20 16:38:54 +00007014 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02007015 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007016 *exparg.lastp = sp;
7017 exparg.lastp = &sp->next;
7018}
7019
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007020/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007021#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007022
7023/* Add the result of glob() to the list */
7024static void
7025addglob(const glob_t *pglob)
7026{
7027 char **p = pglob->gl_pathv;
7028
7029 do {
7030 addfname(*p);
7031 } while (*++p);
7032}
7033static void
7034expandmeta(struct strlist *str /*, int flag*/)
7035{
7036 /* TODO - EXP_REDIR */
7037
7038 while (str) {
7039 char *p;
7040 glob_t pglob;
7041 int i;
7042
7043 if (fflag)
7044 goto nometa;
7045 INT_OFF;
7046 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007047// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7048// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7049//
7050// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7051// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7052// Which means you need to unescape the string, right? Not so fast:
7053// if there _is_ a file named "file\?" (with backslash), it is returned
7054// as "file\?" too (whichever pattern you used to find it, say, "file*").
7055// You DONT KNOW by looking at the result whether you need to unescape it.
7056//
7057// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7058// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7059// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7060// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7061// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7062// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7063 i = glob(p, 0, NULL, &pglob);
7064 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007065 if (p != str->text)
7066 free(p);
7067 switch (i) {
7068 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007069#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007070 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7071 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7072 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007073#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007074 addglob(&pglob);
7075 globfree(&pglob);
7076 INT_ON;
7077 break;
7078 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007079 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007080 globfree(&pglob);
7081 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007082 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007083 *exparg.lastp = str;
7084 rmescapes(str->text, 0);
7085 exparg.lastp = &str->next;
7086 break;
7087 default: /* GLOB_NOSPACE */
7088 globfree(&pglob);
7089 INT_ON;
7090 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7091 }
7092 str = str->next;
7093 }
7094}
7095
7096#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007097/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007098
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007099/*
7100 * Do metacharacter (i.e. *, ?, [...]) expansion.
7101 */
7102static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007103expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007104{
7105 char *p;
7106 const char *cp;
7107 char *start;
7108 char *endname;
7109 int metaflag;
7110 struct stat statb;
7111 DIR *dirp;
7112 struct dirent *dp;
7113 int atend;
7114 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007115 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007116
7117 metaflag = 0;
7118 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007119 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007120 if (*p == '*' || *p == '?')
7121 metaflag = 1;
7122 else if (*p == '[') {
7123 char *q = p + 1;
7124 if (*q == '!')
7125 q++;
7126 for (;;) {
7127 if (*q == '\\')
7128 q++;
7129 if (*q == '/' || *q == '\0')
7130 break;
7131 if (*++q == ']') {
7132 metaflag = 1;
7133 break;
7134 }
7135 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007136 } else {
7137 if (*p == '\\')
7138 esc++;
7139 if (p[esc] == '/') {
7140 if (metaflag)
7141 break;
7142 start = p + esc + 1;
7143 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007144 }
7145 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007146 if (metaflag == 0) { /* we've reached the end of the file name */
7147 if (enddir != expdir)
7148 metaflag++;
7149 p = name;
7150 do {
7151 if (*p == '\\')
7152 p++;
7153 *enddir++ = *p;
7154 } while (*p++);
7155 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7156 addfname(expdir);
7157 return;
7158 }
7159 endname = p;
7160 if (name < start) {
7161 p = name;
7162 do {
7163 if (*p == '\\')
7164 p++;
7165 *enddir++ = *p++;
7166 } while (p < start);
7167 }
7168 if (enddir == expdir) {
7169 cp = ".";
7170 } else if (enddir == expdir + 1 && *expdir == '/') {
7171 cp = "/";
7172 } else {
7173 cp = expdir;
7174 enddir[-1] = '\0';
7175 }
7176 dirp = opendir(cp);
7177 if (dirp == NULL)
7178 return;
7179 if (enddir != expdir)
7180 enddir[-1] = '/';
7181 if (*endname == 0) {
7182 atend = 1;
7183 } else {
7184 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007185 *endname = '\0';
7186 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007187 }
7188 matchdot = 0;
7189 p = start;
7190 if (*p == '\\')
7191 p++;
7192 if (*p == '.')
7193 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007194 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007195 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007196 continue;
7197 if (pmatch(start, dp->d_name)) {
7198 if (atend) {
7199 strcpy(enddir, dp->d_name);
7200 addfname(expdir);
7201 } else {
7202 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7203 continue;
7204 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007205 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007206 }
7207 }
7208 }
7209 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007210 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007211 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007212}
7213
7214static struct strlist *
7215msort(struct strlist *list, int len)
7216{
7217 struct strlist *p, *q = NULL;
7218 struct strlist **lpp;
7219 int half;
7220 int n;
7221
7222 if (len <= 1)
7223 return list;
7224 half = len >> 1;
7225 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007226 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007227 q = p;
7228 p = p->next;
7229 }
7230 q->next = NULL; /* terminate first half of list */
7231 q = msort(list, half); /* sort first half of list */
7232 p = msort(p, len - half); /* sort second half */
7233 lpp = &list;
7234 for (;;) {
7235#if ENABLE_LOCALE_SUPPORT
7236 if (strcoll(p->text, q->text) < 0)
7237#else
7238 if (strcmp(p->text, q->text) < 0)
7239#endif
7240 {
7241 *lpp = p;
7242 lpp = &p->next;
7243 p = *lpp;
7244 if (p == NULL) {
7245 *lpp = q;
7246 break;
7247 }
7248 } else {
7249 *lpp = q;
7250 lpp = &q->next;
7251 q = *lpp;
7252 if (q == NULL) {
7253 *lpp = p;
7254 break;
7255 }
7256 }
7257 }
7258 return list;
7259}
7260
7261/*
7262 * Sort the results of file name expansion. It calculates the number of
7263 * strings to sort and then calls msort (short for merge sort) to do the
7264 * work.
7265 */
7266static struct strlist *
7267expsort(struct strlist *str)
7268{
7269 int len;
7270 struct strlist *sp;
7271
7272 len = 0;
7273 for (sp = str; sp; sp = sp->next)
7274 len++;
7275 return msort(str, len);
7276}
7277
7278static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007279expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007280{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007281 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007282 '*', '?', '[', 0
7283 };
7284 /* TODO - EXP_REDIR */
7285
7286 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007287 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007288 struct strlist **savelastp;
7289 struct strlist *sp;
7290 char *p;
7291
7292 if (fflag)
7293 goto nometa;
7294 if (!strpbrk(str->text, metachars))
7295 goto nometa;
7296 savelastp = exparg.lastp;
7297
7298 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007299 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007300 {
7301 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007302//BUGGY estimation of how long expanded name can be
7303 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007304 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007305 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007306 free(expdir);
7307 if (p != str->text)
7308 free(p);
7309 INT_ON;
7310 if (exparg.lastp == savelastp) {
7311 /*
7312 * no matches
7313 */
7314 nometa:
7315 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007316 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007317 exparg.lastp = &str->next;
7318 } else {
7319 *exparg.lastp = NULL;
7320 *savelastp = sp = expsort(*savelastp);
7321 while (sp->next != NULL)
7322 sp = sp->next;
7323 exparg.lastp = &sp->next;
7324 }
7325 str = str->next;
7326 }
7327}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007328#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007329
7330/*
7331 * Perform variable substitution and command substitution on an argument,
7332 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7333 * perform splitting and file name expansion. When arglist is NULL, perform
7334 * here document expansion.
7335 */
7336static void
7337expandarg(union node *arg, struct arglist *arglist, int flag)
7338{
7339 struct strlist *sp;
7340 char *p;
7341
7342 argbackq = arg->narg.backquote;
7343 STARTSTACKSTR(expdest);
7344 ifsfirst.next = NULL;
7345 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007346 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007347 argstr(arg->narg.text, flag,
7348 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007349 p = _STPUTC('\0', expdest);
7350 expdest = p - 1;
7351 if (arglist == NULL) {
7352 return; /* here document expanded */
7353 }
7354 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007355 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007356 exparg.lastp = &exparg.list;
7357 /*
7358 * TODO - EXP_REDIR
7359 */
7360 if (flag & EXP_FULL) {
7361 ifsbreakup(p, &exparg);
7362 *exparg.lastp = NULL;
7363 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007364 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007365 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007366 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007367 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007368 TRACE(("expandarg: rmescapes:'%s'\n", p));
7369 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007370 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007371 sp->text = p;
7372 *exparg.lastp = sp;
7373 exparg.lastp = &sp->next;
7374 }
7375 if (ifsfirst.next)
7376 ifsfree();
7377 *exparg.lastp = NULL;
7378 if (exparg.list) {
7379 *arglist->lastp = exparg.list;
7380 arglist->lastp = exparg.lastp;
7381 }
7382}
7383
7384/*
7385 * Expand shell variables and backquotes inside a here document.
7386 */
7387static void
7388expandhere(union node *arg, int fd)
7389{
7390 herefd = fd;
Ron Yorston549deab2015-05-18 09:57:51 +02007391 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007392 full_write(fd, stackblock(), expdest - (char *)stackblock());
7393}
7394
7395/*
7396 * Returns true if the pattern matches the string.
7397 */
7398static int
7399patmatch(char *pattern, const char *string)
7400{
Ron Yorston549deab2015-05-18 09:57:51 +02007401 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007402}
7403
7404/*
7405 * See if a pattern matches in a case statement.
7406 */
7407static int
7408casematch(union node *pattern, char *val)
7409{
7410 struct stackmark smark;
7411 int result;
7412
7413 setstackmark(&smark);
7414 argbackq = pattern->narg.backquote;
7415 STARTSTACKSTR(expdest);
7416 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007417 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7418 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007419 STACKSTRNUL(expdest);
7420 result = patmatch(stackblock(), val);
7421 popstackmark(&smark);
7422 return result;
7423}
7424
7425
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007426/* ============ find_command */
7427
7428struct builtincmd {
7429 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007430 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007431 /* unsigned flags; */
7432};
7433#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007434/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007435 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007436#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007437#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007438
7439struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007440 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007441 union param {
7442 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007443 /* index >= 0 for commands without path (slashes) */
7444 /* (TODO: what exactly does the value mean? PATH position?) */
7445 /* index == -1 for commands with slashes */
7446 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007447 const struct builtincmd *cmd;
7448 struct funcnode *func;
7449 } u;
7450};
7451/* values of cmdtype */
7452#define CMDUNKNOWN -1 /* no entry in table for command */
7453#define CMDNORMAL 0 /* command is an executable program */
7454#define CMDFUNCTION 1 /* command is a shell function */
7455#define CMDBUILTIN 2 /* command is a shell builtin */
7456
7457/* action to find_command() */
7458#define DO_ERR 0x01 /* prints errors */
7459#define DO_ABS 0x02 /* checks absolute paths */
7460#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7461#define DO_ALTPATH 0x08 /* using alternate path */
7462#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7463
7464static void find_command(char *, struct cmdentry *, int, const char *);
7465
7466
7467/* ============ Hashing commands */
7468
7469/*
7470 * When commands are first encountered, they are entered in a hash table.
7471 * This ensures that a full path search will not have to be done for them
7472 * on each invocation.
7473 *
7474 * We should investigate converting to a linear search, even though that
7475 * would make the command name "hash" a misnomer.
7476 */
7477
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007478struct tblentry {
7479 struct tblentry *next; /* next entry in hash chain */
7480 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007481 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007482 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007483 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007484};
7485
Denis Vlasenko01631112007-12-16 17:20:38 +00007486static struct tblentry **cmdtable;
7487#define INIT_G_cmdtable() do { \
7488 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7489} while (0)
7490
7491static int builtinloc = -1; /* index in path of %builtin, or -1 */
7492
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007493
7494static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007495tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007496{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007497#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007498 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007499 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007500 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007501 while (*envp)
7502 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007503 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007504 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007505 /* re-exec ourselves with the new arguments */
7506 execve(bb_busybox_exec_path, argv, envp);
7507 /* If they called chroot or otherwise made the binary no longer
7508 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007509 }
7510#endif
7511
7512 repeat:
7513#ifdef SYSV
7514 do {
7515 execve(cmd, argv, envp);
7516 } while (errno == EINTR);
7517#else
7518 execve(cmd, argv, envp);
7519#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007520 if (cmd == (char*) bb_busybox_exec_path) {
7521 /* We already visited ENOEXEC branch below, don't do it again */
7522//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007523 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007524 return;
7525 }
7526 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007527 /* Run "cmd" as a shell script:
7528 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7529 * "If the execve() function fails with ENOEXEC, the shell
7530 * shall execute a command equivalent to having a shell invoked
7531 * with the command name as its first operand,
7532 * with any remaining arguments passed to the new shell"
7533 *
7534 * That is, do not use $SHELL, user's shell, or /bin/sh;
7535 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007536 *
7537 * Note that bash reads ~80 chars of the file, and if it sees
7538 * a zero byte before it sees newline, it doesn't try to
7539 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007540 * message and exit code 126. For one, this prevents attempts
7541 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007542 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007543 char **ap;
7544 char **new;
7545
7546 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007547 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007548 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7549 new[0] = (char*) "ash";
7550 new[1] = cmd;
7551 ap = new + 2;
7552 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007553 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007554 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007555 argv = new;
7556 goto repeat;
7557 }
7558}
7559
7560/*
7561 * Exec a program. Never returns. If you change this routine, you may
7562 * have to change the find_command routine as well.
7563 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007564static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007565static void
7566shellexec(char **argv, const char *path, int idx)
7567{
7568 char *cmdname;
7569 int e;
7570 char **envp;
7571 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007572 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007573
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007574 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007575 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007576 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007577#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007578 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007579#endif
7580 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007581 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007582 if (applet_no >= 0) {
7583 /* We tried execing ourself, but it didn't work.
7584 * Maybe /proc/self/exe doesn't exist?
7585 * Try $PATH search.
7586 */
7587 goto try_PATH;
7588 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007589 e = errno;
7590 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007591 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007592 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007593 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007594 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007595 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007596 if (errno != ENOENT && errno != ENOTDIR)
7597 e = errno;
7598 }
7599 stunalloc(cmdname);
7600 }
7601 }
7602
7603 /* Map to POSIX errors */
7604 switch (e) {
7605 case EACCES:
7606 exerrno = 126;
7607 break;
7608 case ENOENT:
7609 exerrno = 127;
7610 break;
7611 default:
7612 exerrno = 2;
7613 break;
7614 }
7615 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007616 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7617 argv[0], e, suppress_int));
Denys Vlasenko061a0902016-10-25 17:24:25 +02007618 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007619 /* NOTREACHED */
7620}
7621
7622static void
7623printentry(struct tblentry *cmdp)
7624{
7625 int idx;
7626 const char *path;
7627 char *name;
7628
7629 idx = cmdp->param.index;
7630 path = pathval();
7631 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007632 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007633 stunalloc(name);
7634 } while (--idx >= 0);
7635 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7636}
7637
7638/*
7639 * Clear out command entries. The argument specifies the first entry in
7640 * PATH which has changed.
7641 */
7642static void
7643clearcmdentry(int firstchange)
7644{
7645 struct tblentry **tblp;
7646 struct tblentry **pp;
7647 struct tblentry *cmdp;
7648
7649 INT_OFF;
7650 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7651 pp = tblp;
7652 while ((cmdp = *pp) != NULL) {
7653 if ((cmdp->cmdtype == CMDNORMAL &&
7654 cmdp->param.index >= firstchange)
7655 || (cmdp->cmdtype == CMDBUILTIN &&
7656 builtinloc >= firstchange)
7657 ) {
7658 *pp = cmdp->next;
7659 free(cmdp);
7660 } else {
7661 pp = &cmdp->next;
7662 }
7663 }
7664 }
7665 INT_ON;
7666}
7667
7668/*
7669 * Locate a command in the command hash table. If "add" is nonzero,
7670 * add the command to the table if it is not already present. The
7671 * variable "lastcmdentry" is set to point to the address of the link
7672 * pointing to the entry, so that delete_cmd_entry can delete the
7673 * entry.
7674 *
7675 * Interrupts must be off if called with add != 0.
7676 */
7677static struct tblentry **lastcmdentry;
7678
7679static struct tblentry *
7680cmdlookup(const char *name, int add)
7681{
7682 unsigned int hashval;
7683 const char *p;
7684 struct tblentry *cmdp;
7685 struct tblentry **pp;
7686
7687 p = name;
7688 hashval = (unsigned char)*p << 4;
7689 while (*p)
7690 hashval += (unsigned char)*p++;
7691 hashval &= 0x7FFF;
7692 pp = &cmdtable[hashval % CMDTABLESIZE];
7693 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7694 if (strcmp(cmdp->cmdname, name) == 0)
7695 break;
7696 pp = &cmdp->next;
7697 }
7698 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007699 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7700 + strlen(name)
7701 /* + 1 - already done because
7702 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007703 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007704 cmdp->cmdtype = CMDUNKNOWN;
7705 strcpy(cmdp->cmdname, name);
7706 }
7707 lastcmdentry = pp;
7708 return cmdp;
7709}
7710
7711/*
7712 * Delete the command entry returned on the last lookup.
7713 */
7714static void
7715delete_cmd_entry(void)
7716{
7717 struct tblentry *cmdp;
7718
7719 INT_OFF;
7720 cmdp = *lastcmdentry;
7721 *lastcmdentry = cmdp->next;
7722 if (cmdp->cmdtype == CMDFUNCTION)
7723 freefunc(cmdp->param.func);
7724 free(cmdp);
7725 INT_ON;
7726}
7727
7728/*
7729 * Add a new command entry, replacing any existing command entry for
7730 * the same name - except special builtins.
7731 */
7732static void
7733addcmdentry(char *name, struct cmdentry *entry)
7734{
7735 struct tblentry *cmdp;
7736
7737 cmdp = cmdlookup(name, 1);
7738 if (cmdp->cmdtype == CMDFUNCTION) {
7739 freefunc(cmdp->param.func);
7740 }
7741 cmdp->cmdtype = entry->cmdtype;
7742 cmdp->param = entry->u;
7743 cmdp->rehash = 0;
7744}
7745
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007746static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007747hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007748{
7749 struct tblentry **pp;
7750 struct tblentry *cmdp;
7751 int c;
7752 struct cmdentry entry;
7753 char *name;
7754
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007755 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007756 clearcmdentry(0);
7757 return 0;
7758 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007759
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007760 if (*argptr == NULL) {
7761 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7762 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7763 if (cmdp->cmdtype == CMDNORMAL)
7764 printentry(cmdp);
7765 }
7766 }
7767 return 0;
7768 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007769
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007770 c = 0;
7771 while ((name = *argptr) != NULL) {
7772 cmdp = cmdlookup(name, 0);
7773 if (cmdp != NULL
7774 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007775 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7776 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007777 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007778 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007779 find_command(name, &entry, DO_ERR, pathval());
7780 if (entry.cmdtype == CMDUNKNOWN)
7781 c = 1;
7782 argptr++;
7783 }
7784 return c;
7785}
7786
7787/*
7788 * Called when a cd is done. Marks all commands so the next time they
7789 * are executed they will be rehashed.
7790 */
7791static void
7792hashcd(void)
7793{
7794 struct tblentry **pp;
7795 struct tblentry *cmdp;
7796
7797 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7798 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007799 if (cmdp->cmdtype == CMDNORMAL
7800 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007801 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007802 && builtinloc > 0)
7803 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007804 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007805 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007806 }
7807 }
7808}
7809
7810/*
7811 * Fix command hash table when PATH changed.
7812 * Called before PATH is changed. The argument is the new value of PATH;
7813 * pathval() still returns the old value at this point.
7814 * Called with interrupts off.
7815 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007816static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007817changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007818{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007819 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007820 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007821 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007822 int idx_bltin;
7823
7824 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007825 firstchange = 9999; /* assume no change */
7826 idx = 0;
7827 idx_bltin = -1;
7828 for (;;) {
7829 if (*old != *new) {
7830 firstchange = idx;
7831 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007832 || (*old == ':' && *new == '\0')
7833 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007834 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007835 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007836 old = new; /* ignore subsequent differences */
7837 }
7838 if (*new == '\0')
7839 break;
7840 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7841 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007842 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007843 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007844 new++;
7845 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007846 }
7847 if (builtinloc < 0 && idx_bltin >= 0)
7848 builtinloc = idx_bltin; /* zap builtins */
7849 if (builtinloc >= 0 && idx_bltin < 0)
7850 firstchange = 0;
7851 clearcmdentry(firstchange);
7852 builtinloc = idx_bltin;
7853}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007854enum {
7855 TEOF,
7856 TNL,
7857 TREDIR,
7858 TWORD,
7859 TSEMI,
7860 TBACKGND,
7861 TAND,
7862 TOR,
7863 TPIPE,
7864 TLP,
7865 TRP,
7866 TENDCASE,
7867 TENDBQUOTE,
7868 TNOT,
7869 TCASE,
7870 TDO,
7871 TDONE,
7872 TELIF,
7873 TELSE,
7874 TESAC,
7875 TFI,
7876 TFOR,
7877#if ENABLE_ASH_BASH_COMPAT
7878 TFUNCTION,
7879#endif
7880 TIF,
7881 TIN,
7882 TTHEN,
7883 TUNTIL,
7884 TWHILE,
7885 TBEGIN,
7886 TEND
7887};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007888typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007889
Denys Vlasenko888527c2016-10-02 16:54:17 +02007890/* Nth bit indicates if token marks the end of a list */
7891enum {
7892 tokendlist = 0
7893 /* 0 */ | (1u << TEOF)
7894 /* 1 */ | (0u << TNL)
7895 /* 2 */ | (0u << TREDIR)
7896 /* 3 */ | (0u << TWORD)
7897 /* 4 */ | (0u << TSEMI)
7898 /* 5 */ | (0u << TBACKGND)
7899 /* 6 */ | (0u << TAND)
7900 /* 7 */ | (0u << TOR)
7901 /* 8 */ | (0u << TPIPE)
7902 /* 9 */ | (0u << TLP)
7903 /* 10 */ | (1u << TRP)
7904 /* 11 */ | (1u << TENDCASE)
7905 /* 12 */ | (1u << TENDBQUOTE)
7906 /* 13 */ | (0u << TNOT)
7907 /* 14 */ | (0u << TCASE)
7908 /* 15 */ | (1u << TDO)
7909 /* 16 */ | (1u << TDONE)
7910 /* 17 */ | (1u << TELIF)
7911 /* 18 */ | (1u << TELSE)
7912 /* 19 */ | (1u << TESAC)
7913 /* 20 */ | (1u << TFI)
7914 /* 21 */ | (0u << TFOR)
7915#if ENABLE_ASH_BASH_COMPAT
7916 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02007917#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007918 /* 23 */ | (0u << TIF)
7919 /* 24 */ | (0u << TIN)
7920 /* 25 */ | (1u << TTHEN)
7921 /* 26 */ | (0u << TUNTIL)
7922 /* 27 */ | (0u << TWHILE)
7923 /* 28 */ | (0u << TBEGIN)
7924 /* 29 */ | (1u << TEND)
7925 , /* thus far 29 bits used */
7926};
7927
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007928static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02007929 "end of file",
7930 "newline",
7931 "redirection",
7932 "word",
7933 ";",
7934 "&",
7935 "&&",
7936 "||",
7937 "|",
7938 "(",
7939 ")",
7940 ";;",
7941 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007942#define KWDOFFSET 13
7943 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02007944 "!",
7945 "case",
7946 "do",
7947 "done",
7948 "elif",
7949 "else",
7950 "esac",
7951 "fi",
7952 "for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007953#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko888527c2016-10-02 16:54:17 +02007954 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007955#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007956 "if",
7957 "in",
7958 "then",
7959 "until",
7960 "while",
7961 "{",
7962 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007963};
7964
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007965/* Wrapper around strcmp for qsort/bsearch/... */
7966static int
7967pstrcmp(const void *a, const void *b)
7968{
Denys Vlasenko888527c2016-10-02 16:54:17 +02007969 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007970}
7971
7972static const char *const *
7973findkwd(const char *s)
7974{
7975 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007976 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7977 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007978}
7979
7980/*
7981 * Locate and print what a word is...
7982 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007983static int
Ron Yorston3f221112015-08-03 13:47:33 +01007984describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007985{
7986 struct cmdentry entry;
7987 struct tblentry *cmdp;
7988#if ENABLE_ASH_ALIAS
7989 const struct alias *ap;
7990#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007991
7992 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007993
7994 if (describe_command_verbose) {
7995 out1str(command);
7996 }
7997
7998 /* First look at the keywords */
7999 if (findkwd(command)) {
8000 out1str(describe_command_verbose ? " is a shell keyword" : command);
8001 goto out;
8002 }
8003
8004#if ENABLE_ASH_ALIAS
8005 /* Then look at the aliases */
8006 ap = lookupalias(command, 0);
8007 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008008 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008009 out1str("alias ");
8010 printalias(ap);
8011 return 0;
8012 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00008013 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008014 goto out;
8015 }
8016#endif
8017 /* Then check if it is a tracked alias */
8018 cmdp = cmdlookup(command, 0);
8019 if (cmdp != NULL) {
8020 entry.cmdtype = cmdp->cmdtype;
8021 entry.u = cmdp->param;
8022 } else {
8023 /* Finally use brute force */
8024 find_command(command, &entry, DO_ABS, path);
8025 }
8026
8027 switch (entry.cmdtype) {
8028 case CMDNORMAL: {
8029 int j = entry.u.index;
8030 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00008031 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008032 p = command;
8033 } else {
8034 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02008035 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008036 stunalloc(p);
8037 } while (--j >= 0);
8038 }
8039 if (describe_command_verbose) {
8040 out1fmt(" is%s %s",
8041 (cmdp ? " a tracked alias for" : nullstr), p
8042 );
8043 } else {
8044 out1str(p);
8045 }
8046 break;
8047 }
8048
8049 case CMDFUNCTION:
8050 if (describe_command_verbose) {
8051 out1str(" is a shell function");
8052 } else {
8053 out1str(command);
8054 }
8055 break;
8056
8057 case CMDBUILTIN:
8058 if (describe_command_verbose) {
8059 out1fmt(" is a %sshell builtin",
8060 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8061 "special " : nullstr
8062 );
8063 } else {
8064 out1str(command);
8065 }
8066 break;
8067
8068 default:
8069 if (describe_command_verbose) {
8070 out1str(": not found\n");
8071 }
8072 return 127;
8073 }
8074 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008075 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008076 return 0;
8077}
8078
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008079static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008080typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008081{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008082 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008083 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008084 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008085
Denis Vlasenko46846e22007-05-20 13:08:31 +00008086 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008087 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008088 i++;
8089 verbose = 0;
8090 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008091 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008092 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008093 }
8094 return err;
8095}
8096
8097#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008098/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8099static char **
8100parse_command_args(char **argv, const char **path)
8101{
8102 char *cp, c;
8103
8104 for (;;) {
8105 cp = *++argv;
8106 if (!cp)
8107 return NULL;
8108 if (*cp++ != '-')
8109 break;
8110 c = *cp++;
8111 if (!c)
8112 break;
8113 if (c == '-' && !*cp) {
8114 if (!*++argv)
8115 return NULL;
8116 break;
8117 }
8118 do {
8119 switch (c) {
8120 case 'p':
8121 *path = bb_default_path;
8122 break;
8123 default:
8124 /* run 'typecmd' for other options */
8125 return NULL;
8126 }
8127 c = *cp++;
8128 } while (c);
8129 }
8130 return argv;
8131}
8132
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008133static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008134commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008135{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008136 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008137 int c;
8138 enum {
8139 VERIFY_BRIEF = 1,
8140 VERIFY_VERBOSE = 2,
8141 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008142 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008143
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008144 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8145 * never reaches this function.
8146 */
8147
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008148 while ((c = nextopt("pvV")) != '\0')
8149 if (c == 'V')
8150 verify |= VERIFY_VERBOSE;
8151 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008152 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008153#if DEBUG
8154 else if (c != 'p')
8155 abort();
8156#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008157 else
8158 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008159
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008160 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008161 cmd = *argptr;
8162 if (/*verify && */ cmd)
8163 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008164
8165 return 0;
8166}
8167#endif
8168
8169
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008170/*static int funcblocksize; // size of structures in function */
8171/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008172static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008173static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008174
Eric Andersencb57d552001-06-28 07:25:16 +00008175/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008176#define EV_EXIT 01 /* exit after evaluating tree */
8177#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008178
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008179static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008180 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8181 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8182 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8183 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8184 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8185 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8186 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8187 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8188 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8189 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8190 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8191 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8192 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8193 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8194 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8195 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8196 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008197#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008198 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008199#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008200 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8201 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8202 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8203 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8204 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8205 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8206 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8207 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8208 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008209};
8210
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008211static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008212
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008213static int
8214sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008215{
8216 while (lp) {
8217 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008218 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008219 lp = lp->next;
8220 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008221 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008222}
8223
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008224static int
8225calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008226{
8227 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008228 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008229 funcblocksize += nodesize[n->type];
8230 switch (n->type) {
8231 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008232 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8233 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8234 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008235 break;
8236 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008237 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008238 break;
8239 case NREDIR:
8240 case NBACKGND:
8241 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008242 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8243 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008244 break;
8245 case NAND:
8246 case NOR:
8247 case NSEMI:
8248 case NWHILE:
8249 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008250 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8251 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008252 break;
8253 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008254 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8255 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8256 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008257 break;
8258 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008259 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008260 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8261 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008262 break;
8263 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008264 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8265 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008266 break;
8267 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008268 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8269 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8270 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008271 break;
8272 case NDEFUN:
8273 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008274 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008275 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008276 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008277 break;
8278 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008279#if ENABLE_ASH_BASH_COMPAT
8280 case NTO2:
8281#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008282 case NCLOBBER:
8283 case NFROM:
8284 case NFROMTO:
8285 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008286 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8287 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008288 break;
8289 case NTOFD:
8290 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008291 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8292 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008293 break;
8294 case NHERE:
8295 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008296 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8297 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008298 break;
8299 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008300 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008301 break;
8302 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008303 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008304}
8305
8306static char *
8307nodeckstrdup(char *s)
8308{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008309 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008310 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008311}
8312
8313static union node *copynode(union node *);
8314
8315static struct nodelist *
8316copynodelist(struct nodelist *lp)
8317{
8318 struct nodelist *start;
8319 struct nodelist **lpp;
8320
8321 lpp = &start;
8322 while (lp) {
8323 *lpp = funcblock;
8324 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8325 (*lpp)->n = copynode(lp->n);
8326 lp = lp->next;
8327 lpp = &(*lpp)->next;
8328 }
8329 *lpp = NULL;
8330 return start;
8331}
8332
8333static union node *
8334copynode(union node *n)
8335{
8336 union node *new;
8337
8338 if (n == NULL)
8339 return NULL;
8340 new = funcblock;
8341 funcblock = (char *) funcblock + nodesize[n->type];
8342
8343 switch (n->type) {
8344 case NCMD:
8345 new->ncmd.redirect = copynode(n->ncmd.redirect);
8346 new->ncmd.args = copynode(n->ncmd.args);
8347 new->ncmd.assign = copynode(n->ncmd.assign);
8348 break;
8349 case NPIPE:
8350 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008351 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008352 break;
8353 case NREDIR:
8354 case NBACKGND:
8355 case NSUBSHELL:
8356 new->nredir.redirect = copynode(n->nredir.redirect);
8357 new->nredir.n = copynode(n->nredir.n);
8358 break;
8359 case NAND:
8360 case NOR:
8361 case NSEMI:
8362 case NWHILE:
8363 case NUNTIL:
8364 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8365 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8366 break;
8367 case NIF:
8368 new->nif.elsepart = copynode(n->nif.elsepart);
8369 new->nif.ifpart = copynode(n->nif.ifpart);
8370 new->nif.test = copynode(n->nif.test);
8371 break;
8372 case NFOR:
8373 new->nfor.var = nodeckstrdup(n->nfor.var);
8374 new->nfor.body = copynode(n->nfor.body);
8375 new->nfor.args = copynode(n->nfor.args);
8376 break;
8377 case NCASE:
8378 new->ncase.cases = copynode(n->ncase.cases);
8379 new->ncase.expr = copynode(n->ncase.expr);
8380 break;
8381 case NCLIST:
8382 new->nclist.body = copynode(n->nclist.body);
8383 new->nclist.pattern = copynode(n->nclist.pattern);
8384 new->nclist.next = copynode(n->nclist.next);
8385 break;
8386 case NDEFUN:
8387 case NARG:
8388 new->narg.backquote = copynodelist(n->narg.backquote);
8389 new->narg.text = nodeckstrdup(n->narg.text);
8390 new->narg.next = copynode(n->narg.next);
8391 break;
8392 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008393#if ENABLE_ASH_BASH_COMPAT
8394 case NTO2:
8395#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008396 case NCLOBBER:
8397 case NFROM:
8398 case NFROMTO:
8399 case NAPPEND:
8400 new->nfile.fname = copynode(n->nfile.fname);
8401 new->nfile.fd = n->nfile.fd;
8402 new->nfile.next = copynode(n->nfile.next);
8403 break;
8404 case NTOFD:
8405 case NFROMFD:
8406 new->ndup.vname = copynode(n->ndup.vname);
8407 new->ndup.dupfd = n->ndup.dupfd;
8408 new->ndup.fd = n->ndup.fd;
8409 new->ndup.next = copynode(n->ndup.next);
8410 break;
8411 case NHERE:
8412 case NXHERE:
8413 new->nhere.doc = copynode(n->nhere.doc);
8414 new->nhere.fd = n->nhere.fd;
8415 new->nhere.next = copynode(n->nhere.next);
8416 break;
8417 case NNOT:
8418 new->nnot.com = copynode(n->nnot.com);
8419 break;
8420 };
8421 new->type = n->type;
8422 return new;
8423}
8424
8425/*
8426 * Make a copy of a parse tree.
8427 */
8428static struct funcnode *
8429copyfunc(union node *n)
8430{
8431 struct funcnode *f;
8432 size_t blocksize;
8433
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008434 /*funcstringsize = 0;*/
8435 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8436 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008437 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008438 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008439 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008440 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008441 return f;
8442}
8443
8444/*
8445 * Define a shell function.
8446 */
8447static void
8448defun(char *name, union node *func)
8449{
8450 struct cmdentry entry;
8451
8452 INT_OFF;
8453 entry.cmdtype = CMDFUNCTION;
8454 entry.u.func = copyfunc(func);
8455 addcmdentry(name, &entry);
8456 INT_ON;
8457}
8458
Denis Vlasenko4b875702009-03-19 13:30:04 +00008459/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008460#define SKIPBREAK (1 << 0)
8461#define SKIPCONT (1 << 1)
8462#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008463static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008464static int skipcount; /* number of levels to skip */
8465static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008466static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008467
Denis Vlasenko4b875702009-03-19 13:30:04 +00008468/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008469static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008470
Denis Vlasenko4b875702009-03-19 13:30:04 +00008471/* Called to execute a trap.
8472 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008473 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008474 *
8475 * Perhaps we should avoid entering new trap handlers
8476 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008477 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008478static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008479dotrap(void)
8480{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008481 uint8_t *g;
8482 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008483 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008484
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008485 if (!pending_sig)
8486 return;
8487
8488 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008489 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008490 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008491
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008492 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008493 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008494 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008495
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008496 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008497 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008498
8499 if (evalskip) {
8500 pending_sig = sig;
8501 break;
8502 }
8503
8504 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008505 /* non-trapped SIGINT is handled separately by raise_interrupt,
8506 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008507 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008508 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008509
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008510 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008511 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008512 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008513 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008514 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008515 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008516 exitstatus = last_status;
8517 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008518}
8519
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008520/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008521static int evalloop(union node *, int);
8522static int evalfor(union node *, int);
8523static int evalcase(union node *, int);
8524static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008525static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008526static int evalpipe(union node *, int);
8527static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008528static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008529static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008530
Eric Andersen62483552001-07-10 06:09:16 +00008531/*
Eric Andersenc470f442003-07-28 09:56:35 +00008532 * Evaluate a parse tree. The value is left in the global variable
8533 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008534 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008535static int
Eric Andersenc470f442003-07-28 09:56:35 +00008536evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008537{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008538 struct jmploc *volatile savehandler = exception_handler;
8539 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008540 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008541 int (*evalfn)(union node *, int);
8542 int status = 0;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008543 int int_level;
8544
8545 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008546
Eric Andersenc470f442003-07-28 09:56:35 +00008547 if (n == NULL) {
8548 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008549 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008550 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008551 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008552
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008553 dotrap();
8554
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008555 exception_handler = &jmploc;
8556 {
8557 int err = setjmp(jmploc.loc);
8558 if (err) {
8559 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008560 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008561 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8562 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008563 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008564 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008565 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008566 TRACE(("exception %d in evaltree, propagating err=%d\n",
8567 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008568 exception_handler = savehandler;
8569 longjmp(exception_handler->loc, err);
8570 }
8571 }
8572
Eric Andersenc470f442003-07-28 09:56:35 +00008573 switch (n->type) {
8574 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008575#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008576 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008577 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008578 break;
8579#endif
8580 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008581 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008582 goto setstatus;
8583 case NREDIR:
8584 expredir(n->nredir.redirect);
8585 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8586 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008587 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008588 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008589 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008590 goto setstatus;
8591 case NCMD:
8592 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008593 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008594 if (eflag && !(flags & EV_TESTED))
8595 checkexit = ~0;
8596 goto calleval;
8597 case NFOR:
8598 evalfn = evalfor;
8599 goto calleval;
8600 case NWHILE:
8601 case NUNTIL:
8602 evalfn = evalloop;
8603 goto calleval;
8604 case NSUBSHELL:
Rostislav Skudnov204c7fb2016-09-16 19:04:02 +00008605 evalfn = evalsubshell;
8606 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008607 case NBACKGND:
8608 evalfn = evalsubshell;
8609 goto calleval;
8610 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:
8655 defun(n->narg.text, n->narg.next);
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 Vlasenko4e19a9c2008-07-26 13:45:57 +00008664
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008665 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008666 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008667
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008668 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008669 /* Order of checks below is important:
8670 * signal handlers trigger before exit caused by "set -e".
8671 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008672 dotrap();
8673
8674 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008675 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008676 if (flags & EV_EXIT)
8677 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008678
8679 RESTORE_INT(int_level);
8680 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008681
8682 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008683}
8684
Eric Andersenc470f442003-07-28 09:56:35 +00008685#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8686static
8687#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008688int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008689
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008690static int
8691skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008692{
8693 int skip = evalskip;
8694
8695 switch (skip) {
8696 case 0:
8697 break;
8698 case SKIPBREAK:
8699 case SKIPCONT:
8700 if (--skipcount <= 0) {
8701 evalskip = 0;
8702 break;
8703 }
8704 skip = SKIPBREAK;
8705 break;
8706 }
8707 return skip;
8708}
8709
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008710static int
Eric Andersenc470f442003-07-28 09:56:35 +00008711evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008712{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008713 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008714 int status;
8715
8716 loopnest++;
8717 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008718 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008719 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008720 int i;
8721
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008722 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008723 skip = skiploop();
8724 if (skip == SKIPFUNC)
8725 status = i;
8726 if (skip)
8727 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008728 if (n->type != NWHILE)
8729 i = !i;
8730 if (i != 0)
8731 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008732 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008733 skip = skiploop();
8734 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008735 loopnest--;
8736
8737 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008738}
8739
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008740static int
Eric Andersenc470f442003-07-28 09:56:35 +00008741evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008742{
8743 struct arglist arglist;
8744 union node *argp;
8745 struct strlist *sp;
8746 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008747 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008748
8749 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008750 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008751 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008752 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008753 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008754 }
8755 *arglist.lastp = NULL;
8756
Eric Andersencb57d552001-06-28 07:25:16 +00008757 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008758 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008759 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008760 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008761 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008762 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008763 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008764 }
8765 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008766 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008767
8768 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008769}
8770
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008771static int
Eric Andersenc470f442003-07-28 09:56:35 +00008772evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008773{
8774 union node *cp;
8775 union node *patp;
8776 struct arglist arglist;
8777 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008778 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008779
8780 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008781 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008782 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008783 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008784 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8785 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008786 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008787 /* Ensure body is non-empty as otherwise
8788 * EV_EXIT may prevent us from setting the
8789 * exit status.
8790 */
8791 if (evalskip == 0 && cp->nclist.body) {
8792 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008793 }
8794 goto out;
8795 }
8796 }
8797 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008798 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008799 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008800
8801 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008802}
8803
Eric Andersenc470f442003-07-28 09:56:35 +00008804/*
8805 * Kick off a subshell to evaluate a tree.
8806 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008807static int
Eric Andersenc470f442003-07-28 09:56:35 +00008808evalsubshell(union node *n, int flags)
8809{
8810 struct job *jp;
8811 int backgnd = (n->type == NBACKGND);
8812 int status;
8813
8814 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008815 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008816 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008817 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008818 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008819 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008820 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008821 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008822 flags |= EV_EXIT;
8823 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008824 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008825 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008826 redirect(n->nredir.redirect, 0);
8827 evaltreenr(n->nredir.n, flags);
8828 /* never returns */
8829 }
8830 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008831 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008832 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008833 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008834 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008835}
8836
Eric Andersenc470f442003-07-28 09:56:35 +00008837/*
8838 * Compute the names of the files in a redirection list.
8839 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008840static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008841static void
8842expredir(union node *n)
8843{
8844 union node *redir;
8845
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008846 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008847 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008848
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008849 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008850 fn.lastp = &fn.list;
8851 switch (redir->type) {
8852 case NFROMTO:
8853 case NFROM:
8854 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008855#if ENABLE_ASH_BASH_COMPAT
8856 case NTO2:
8857#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008858 case NCLOBBER:
8859 case NAPPEND:
8860 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008861 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008862#if ENABLE_ASH_BASH_COMPAT
8863 store_expfname:
8864#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008865#if 0
8866// By the design of stack allocator, the loop of this kind:
8867// while true; do while true; do break; done </dev/null; done
8868// will look like a memory leak: ash plans to free expfname's
8869// of "/dev/null" as soon as it finishes running the loop
8870// (in this case, never).
8871// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008872 if (redir->nfile.expfname)
8873 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008874// It results in corrupted state of stacked allocations.
8875#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008876 redir->nfile.expfname = fn.list->text;
8877 break;
8878 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008879 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008880 if (redir->ndup.vname) {
8881 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008882 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008883 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008884#if ENABLE_ASH_BASH_COMPAT
8885//FIXME: we used expandarg with different args!
8886 if (!isdigit_str9(fn.list->text)) {
8887 /* >&file, not >&fd */
8888 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8889 ash_msg_and_raise_error("redir error");
8890 redir->type = NTO2;
8891 goto store_expfname;
8892 }
8893#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008894 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008895 }
8896 break;
8897 }
8898 }
8899}
8900
Eric Andersencb57d552001-06-28 07:25:16 +00008901/*
Eric Andersencb57d552001-06-28 07:25:16 +00008902 * Evaluate a pipeline. All the processes in the pipeline are children
8903 * of the process creating the pipeline. (This differs from some versions
8904 * of the shell, which make the last process in a pipeline the parent
8905 * of all the rest.)
8906 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008907static int
Eric Andersenc470f442003-07-28 09:56:35 +00008908evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008909{
8910 struct job *jp;
8911 struct nodelist *lp;
8912 int pipelen;
8913 int prevfd;
8914 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008915 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008916
Eric Andersenc470f442003-07-28 09:56:35 +00008917 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008918 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008919 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008920 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008921 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008922 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008923 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008924 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008925 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008926 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008927 pip[1] = -1;
8928 if (lp->next) {
8929 if (pipe(pip) < 0) {
8930 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008931 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008932 }
8933 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008934 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008935 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008936 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008937 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008938 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008939 if (prevfd > 0) {
8940 dup2(prevfd, 0);
8941 close(prevfd);
8942 }
8943 if (pip[1] > 1) {
8944 dup2(pip[1], 1);
8945 close(pip[1]);
8946 }
Eric Andersenc470f442003-07-28 09:56:35 +00008947 evaltreenr(lp->n, flags);
8948 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008949 }
8950 if (prevfd >= 0)
8951 close(prevfd);
8952 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008953 /* Don't want to trigger debugging */
8954 if (pip[1] != -1)
8955 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008956 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008957 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008958 status = waitforjob(jp);
8959 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008960 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008961 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008962
8963 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008964}
8965
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008966/*
8967 * Controls whether the shell is interactive or not.
8968 */
8969static void
8970setinteractive(int on)
8971{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008972 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008973
8974 if (++on == is_interactive)
8975 return;
8976 is_interactive = on;
8977 setsignal(SIGINT);
8978 setsignal(SIGQUIT);
8979 setsignal(SIGTERM);
8980#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8981 if (is_interactive > 1) {
8982 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008983 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008984
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008985 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008986 /* note: ash and hush share this string */
8987 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008988 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8989 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008990 bb_banner,
8991 "built-in shell (ash)"
8992 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008993 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008994 }
8995 }
8996#endif
8997}
8998
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008999static void
9000optschanged(void)
9001{
9002#if DEBUG
9003 opentrace();
9004#endif
9005 setinteractive(iflag);
9006 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009007#if ENABLE_FEATURE_EDITING_VI
9008 if (viflag)
9009 line_input_state->flags |= VI_MODE;
9010 else
9011 line_input_state->flags &= ~VI_MODE;
9012#else
9013 viflag = 0; /* forcibly keep the option off */
9014#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009015}
9016
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009017static struct localvar *localvars;
9018
9019/*
9020 * Called after a function returns.
9021 * Interrupts must be off.
9022 */
9023static void
9024poplocalvars(void)
9025{
9026 struct localvar *lvp;
9027 struct var *vp;
9028
9029 while ((lvp = localvars) != NULL) {
9030 localvars = lvp->next;
9031 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02009032 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009033 if (vp == NULL) { /* $- saved */
9034 memcpy(optlist, lvp->text, sizeof(optlist));
9035 free((char*)lvp->text);
9036 optschanged();
9037 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009038 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009039 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009040 if (vp->var_func)
9041 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009042 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009043 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009044 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009045 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009046 }
9047 free(lvp);
9048 }
9049}
9050
9051static int
9052evalfun(struct funcnode *func, int argc, char **argv, int flags)
9053{
9054 volatile struct shparam saveparam;
9055 struct localvar *volatile savelocalvars;
9056 struct jmploc *volatile savehandler;
9057 struct jmploc jmploc;
9058 int e;
9059
9060 saveparam = shellparam;
9061 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009062 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009063 e = setjmp(jmploc.loc);
9064 if (e) {
9065 goto funcdone;
9066 }
9067 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009068 exception_handler = &jmploc;
9069 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009070 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009071 func->count++;
9072 funcnest++;
9073 INT_ON;
9074 shellparam.nparam = argc - 1;
9075 shellparam.p = argv + 1;
9076#if ENABLE_ASH_GETOPTS
9077 shellparam.optind = 1;
9078 shellparam.optoff = -1;
9079#endif
9080 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009081 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009082 INT_OFF;
9083 funcnest--;
9084 freefunc(func);
9085 poplocalvars();
9086 localvars = savelocalvars;
9087 freeparam(&shellparam);
9088 shellparam = saveparam;
9089 exception_handler = savehandler;
9090 INT_ON;
9091 evalskip &= ~SKIPFUNC;
9092 return e;
9093}
9094
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009095/*
9096 * Make a variable a local variable. When a variable is made local, it's
9097 * value and flags are saved in a localvar structure. The saved values
9098 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009099 * "-" as a special case: it makes changes to "set +-options" local
9100 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009101 */
9102static void
9103mklocal(char *name)
9104{
9105 struct localvar *lvp;
9106 struct var **vpp;
9107 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009108 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009109
9110 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009111 /* Cater for duplicate "local". Examples:
9112 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9113 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9114 */
9115 lvp = localvars;
9116 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009117 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009118 if (eq)
9119 setvareq(name, 0);
9120 /* else:
9121 * it's a duplicate "local VAR" declaration, do nothing
9122 */
9123 return;
9124 }
9125 lvp = lvp->next;
9126 }
9127
9128 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009129 if (LONE_DASH(name)) {
9130 char *p;
9131 p = ckmalloc(sizeof(optlist));
9132 lvp->text = memcpy(p, optlist, sizeof(optlist));
9133 vp = NULL;
9134 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009135 vpp = hashvar(name);
9136 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009137 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009138 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009139 if (eq)
9140 setvareq(name, VSTRFIXED);
9141 else
9142 setvar(name, NULL, VSTRFIXED);
9143 vp = *vpp; /* the new variable */
9144 lvp->flags = VUNSET;
9145 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009146 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009147 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009148 /* make sure neither "struct var" nor string gets freed
9149 * during (un)setting:
9150 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009151 vp->flags |= VSTRFIXED|VTEXTFIXED;
9152 if (eq)
9153 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009154 else
9155 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009156 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009157 }
9158 }
9159 lvp->vp = vp;
9160 lvp->next = localvars;
9161 localvars = lvp;
9162 INT_ON;
9163}
9164
9165/*
9166 * The "local" command.
9167 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009168static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009169localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009170{
9171 char *name;
9172
Ron Yorstonef2386b2015-10-29 16:19:14 +00009173 if (!funcnest)
9174 ash_msg_and_raise_error("not in a function");
9175
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009176 argv = argptr;
9177 while ((name = *argv++) != NULL) {
9178 mklocal(name);
9179 }
9180 return 0;
9181}
9182
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009183static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009184falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009185{
9186 return 1;
9187}
9188
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009189static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009190truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009191{
9192 return 0;
9193}
9194
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009195static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009196execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009197{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009198 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009199 iflag = 0; /* exit on error */
9200 mflag = 0;
9201 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009202 /* We should set up signals for "exec CMD"
9203 * the same way as for "CMD" without "exec".
9204 * But optschanged->setinteractive->setsignal
9205 * still thought we are a root shell. Therefore, for example,
9206 * SIGQUIT is still set to IGN. Fix it:
9207 */
9208 shlvl++;
9209 setsignal(SIGQUIT);
9210 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9211 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9212 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9213
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009214 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009215 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009216 }
9217 return 0;
9218}
9219
9220/*
9221 * The return command.
9222 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009223static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009224returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009225{
9226 /*
9227 * If called outside a function, do what ksh does;
9228 * skip the rest of the file.
9229 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009230 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009231 return argv[1] ? number(argv[1]) : exitstatus;
9232}
9233
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009234/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009235static int breakcmd(int, char **) FAST_FUNC;
9236static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009237static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009238static int exitcmd(int, char **) FAST_FUNC;
9239static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009240#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009241static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009242#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009243#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009244static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009245#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009246#if MAX_HISTORY
9247static int historycmd(int, char **) FAST_FUNC;
9248#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009249#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009250static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009251#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009252static int readcmd(int, char **) FAST_FUNC;
9253static int setcmd(int, char **) FAST_FUNC;
9254static int shiftcmd(int, char **) FAST_FUNC;
9255static int timescmd(int, char **) FAST_FUNC;
9256static int trapcmd(int, char **) FAST_FUNC;
9257static int umaskcmd(int, char **) FAST_FUNC;
9258static int unsetcmd(int, char **) FAST_FUNC;
9259static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009260
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009261#define BUILTIN_NOSPEC "0"
9262#define BUILTIN_SPECIAL "1"
9263#define BUILTIN_REGULAR "2"
9264#define BUILTIN_SPEC_REG "3"
9265#define BUILTIN_ASSIGN "4"
9266#define BUILTIN_SPEC_ASSG "5"
9267#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009268#define BUILTIN_SPEC_REG_ASSG "7"
9269
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009270/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009271#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009272static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009273#endif
9274#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009275static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009276#endif
9277#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009278static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009279#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009280
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009281/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009282static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009283 { BUILTIN_SPEC_REG "." , dotcmd },
9284 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009285#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009286 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009287#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009288 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009289#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009290#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009291#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009292 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009293#endif
9294#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009295 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009296#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009297 { BUILTIN_SPEC_REG "break" , breakcmd },
9298 { BUILTIN_REGULAR "cd" , cdcmd },
9299 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009300#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009301 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009302#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009303 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009304#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009305 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009306#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009307 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009308 { BUILTIN_SPEC_REG "exec" , execcmd },
9309 { BUILTIN_SPEC_REG "exit" , exitcmd },
9310 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9311 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009312#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009313 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009314#endif
9315#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009316 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009317#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009318 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009319#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009320 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009321#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009322#if MAX_HISTORY
9323 { BUILTIN_NOSPEC "history" , historycmd },
9324#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009325#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009326 { BUILTIN_REGULAR "jobs" , jobscmd },
9327 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009328#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009329#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009330 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009331#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009332 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009333#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009334 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009335#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009336 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9337 { BUILTIN_REGULAR "read" , readcmd },
9338 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9339 { BUILTIN_SPEC_REG "return" , returncmd },
9340 { BUILTIN_SPEC_REG "set" , setcmd },
9341 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009342#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009343 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009344#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009345#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009346 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009347#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009348 { BUILTIN_SPEC_REG "times" , timescmd },
9349 { BUILTIN_SPEC_REG "trap" , trapcmd },
9350 { BUILTIN_REGULAR "true" , truecmd },
9351 { BUILTIN_NOSPEC "type" , typecmd },
9352 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9353 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009354#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009355 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009356#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009357 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9358 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009359};
9360
Denis Vlasenko80591b02008-03-25 07:49:43 +00009361/* Should match the above table! */
9362#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009363 /* . : */ 2 + \
9364 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9365 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9366 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9367 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9368 /* break cd cddir */ 3)
9369#define EVALCMD (COMMANDCMD + \
9370 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9371 /* continue */ 1 + \
9372 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9373 0)
9374#define EXECCMD (EVALCMD + \
9375 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009376
9377/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009378 * Search the table of builtin commands.
9379 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009380static int
9381pstrcmp1(const void *a, const void *b)
9382{
9383 return strcmp((char*)a, *(char**)b + 1);
9384}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009385static struct builtincmd *
9386find_builtin(const char *name)
9387{
9388 struct builtincmd *bp;
9389
9390 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009391 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009392 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009393 );
9394 return bp;
9395}
9396
9397/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009398 * Execute a simple command.
9399 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009400static int
9401isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009402{
9403 const char *q = endofname(p);
9404 if (p == q)
9405 return 0;
9406 return *q == '=';
9407}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009408static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009409bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009410{
9411 /* Preserve exitstatus of a previous possible redirection
9412 * as POSIX mandates */
9413 return back_exitstatus;
9414}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009415static int
Eric Andersenc470f442003-07-28 09:56:35 +00009416evalcommand(union node *cmd, int flags)
9417{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009418 static const struct builtincmd null_bltin = {
9419 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009420 };
Eric Andersenc470f442003-07-28 09:56:35 +00009421 struct stackmark smark;
9422 union node *argp;
9423 struct arglist arglist;
9424 struct arglist varlist;
9425 char **argv;
9426 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009427 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009428 struct cmdentry cmdentry;
9429 struct job *jp;
9430 char *lastarg;
9431 const char *path;
9432 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009433 int status;
9434 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009435 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009436 smallint cmd_is_exec;
9437 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009438
9439 /* First expand the arguments. */
9440 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9441 setstackmark(&smark);
9442 back_exitstatus = 0;
9443
9444 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009445 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009446 varlist.lastp = &varlist.list;
9447 *varlist.lastp = NULL;
9448 arglist.lastp = &arglist.list;
9449 *arglist.lastp = NULL;
9450
9451 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009452 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009453 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9454 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9455 }
9456
Eric Andersenc470f442003-07-28 09:56:35 +00009457 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9458 struct strlist **spp;
9459
9460 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009461 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009462 expandarg(argp, &arglist, EXP_VARTILDE);
9463 else
9464 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9465
Eric Andersenc470f442003-07-28 09:56:35 +00009466 for (sp = *spp; sp; sp = sp->next)
9467 argc++;
9468 }
9469
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009470 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
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)) {
Eric Andersenc470f442003-07-28 09:56:35 +00009633 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009634 int i = exception_type;
Denys Vlasenko061a0902016-10-25 17:24:25 +02009635 if (i == EXEXIT)
Eric Andersenc470f442003-07-28 09:56:35 +00009636 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009637 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009638 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009639 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009640 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009641 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009642 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009643 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009644 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009645 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009646 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009647 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009648 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009649 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009650
9651 case CMDFUNCTION:
9652 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009653 /* See above for the rationale */
9654 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009655 if (evalfun(cmdentry.u.func, argc, argv, flags))
9656 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009657 readstatus:
9658 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009659 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009660 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009661
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009662 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009663 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009664 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009665 /* dsl: I think this is intended to be used to support
9666 * '_' in 'vi' command mode during line editing...
9667 * However I implemented that within libedit itself.
9668 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009669 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009670 }
Eric Andersenc470f442003-07-28 09:56:35 +00009671 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009672
9673 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009674}
9675
9676static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009677evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009678{
Eric Andersenc470f442003-07-28 09:56:35 +00009679 char *volatile savecmdname;
9680 struct jmploc *volatile savehandler;
9681 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009682 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009683 int i;
9684
9685 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009686 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009687 i = setjmp(jmploc.loc);
9688 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009689 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009690 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009691 commandname = argv[0];
9692 argptr = argv + 1;
9693 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009694 if (cmd == EVALCMD)
9695 status = evalcmd(argc, argv, flags);
9696 else
9697 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009698 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009699 status |= ferror(stdout);
9700 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009701 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009702 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009703 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009704 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009705
9706 return i;
9707}
9708
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009709static int
9710goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009711{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009712 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009713}
9714
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009715
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009716/*
9717 * Search for a command. This is called before we fork so that the
9718 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009719 * the child. The check for "goodname" is an overly conservative
9720 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009721 */
Eric Andersenc470f442003-07-28 09:56:35 +00009722static void
9723prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009724{
9725 struct cmdentry entry;
9726
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009727 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9728 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009729}
9730
Eric Andersencb57d552001-06-28 07:25:16 +00009731
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009732/* ============ Builtin commands
9733 *
9734 * Builtin commands whose functions are closely tied to evaluation
9735 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009736 */
9737
9738/*
Eric Andersencb57d552001-06-28 07:25:16 +00009739 * Handle break and continue commands. Break, continue, and return are
9740 * all handled by setting the evalskip flag. The evaluation routines
9741 * above all check this flag, and if it is set they start skipping
9742 * commands rather than executing them. The variable skipcount is
9743 * the number of loops to break/continue, or the number of function
9744 * levels to return. (The latter is always 1.) It should probably
9745 * be an error to break out of more loops than exist, but it isn't
9746 * in the standard shell so we don't make it one here.
9747 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009748static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009749breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009750{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009751 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009752
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009753 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009754 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009755 if (n > loopnest)
9756 n = loopnest;
9757 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009758 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009759 skipcount = n;
9760 }
9761 return 0;
9762}
9763
Eric Andersenc470f442003-07-28 09:56:35 +00009764
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009765/* ============ input.c
9766 *
Eric Andersen90898442003-08-06 11:20:52 +00009767 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009768 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009769
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009770enum {
9771 INPUT_PUSH_FILE = 1,
9772 INPUT_NOFILE_OK = 2,
9773};
Eric Andersencb57d552001-06-28 07:25:16 +00009774
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009775static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009776/* values of checkkwd variable */
9777#define CHKALIAS 0x1
9778#define CHKKWD 0x2
9779#define CHKNL 0x4
9780
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009781/*
9782 * Push a string back onto the input at this current parsefile level.
9783 * We handle aliases this way.
9784 */
9785#if !ENABLE_ASH_ALIAS
9786#define pushstring(s, ap) pushstring(s)
9787#endif
9788static void
9789pushstring(char *s, struct alias *ap)
9790{
9791 struct strpush *sp;
9792 int len;
9793
9794 len = strlen(s);
9795 INT_OFF;
9796 if (g_parsefile->strpush) {
9797 sp = ckzalloc(sizeof(*sp));
9798 sp->prev = g_parsefile->strpush;
9799 } else {
9800 sp = &(g_parsefile->basestrpush);
9801 }
9802 g_parsefile->strpush = sp;
9803 sp->prev_string = g_parsefile->next_to_pgetc;
9804 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009805 sp->unget = g_parsefile->unget;
9806 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009807#if ENABLE_ASH_ALIAS
9808 sp->ap = ap;
9809 if (ap) {
9810 ap->flag |= ALIASINUSE;
9811 sp->string = s;
9812 }
9813#endif
9814 g_parsefile->next_to_pgetc = s;
9815 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009816 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009817 INT_ON;
9818}
9819
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009820static void
9821popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009822{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009823 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009824
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009825 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009826#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009827 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009828 if (g_parsefile->next_to_pgetc[-1] == ' '
9829 || g_parsefile->next_to_pgetc[-1] == '\t'
9830 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009831 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009832 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009833 if (sp->string != sp->ap->val) {
9834 free(sp->string);
9835 }
9836 sp->ap->flag &= ~ALIASINUSE;
9837 if (sp->ap->flag & ALIASDEAD) {
9838 unalias(sp->ap->name);
9839 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009840 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009841#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009842 g_parsefile->next_to_pgetc = sp->prev_string;
9843 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009844 g_parsefile->unget = sp->unget;
9845 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009846 g_parsefile->strpush = sp->prev;
9847 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009848 free(sp);
9849 INT_ON;
9850}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009851
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009852static int
9853preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009854{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009855 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009856 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009857
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009858 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009859#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009860 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009861 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009862 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009863 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009864 int timeout = -1;
9865# if ENABLE_ASH_IDLE_TIMEOUT
9866 if (iflag) {
9867 const char *tmout_var = lookupvar("TMOUT");
9868 if (tmout_var) {
9869 timeout = atoi(tmout_var) * 1000;
9870 if (timeout <= 0)
9871 timeout = -1;
9872 }
9873 }
9874# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009875# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009876 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009877# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009878 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009879 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009880 if (nr == 0) {
9881 /* Ctrl+C pressed */
9882 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009883 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009884 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009885 raise(SIGINT);
9886 return 1;
9887 }
Eric Andersenc470f442003-07-28 09:56:35 +00009888 goto retry;
9889 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009890 if (nr < 0) {
9891 if (errno == 0) {
9892 /* Ctrl+D pressed */
9893 nr = 0;
9894 }
9895# if ENABLE_ASH_IDLE_TIMEOUT
9896 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009897 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009898 exitshell();
9899 }
9900# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009901 }
Eric Andersencb57d552001-06-28 07:25:16 +00009902 }
9903#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009904 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009905#endif
9906
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009907#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009908 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009909 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009910 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009911 if (flags >= 0 && (flags & O_NONBLOCK)) {
9912 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009913 if (fcntl(0, F_SETFL, flags) >= 0) {
9914 out2str("sh: turning off NDELAY mode\n");
9915 goto retry;
9916 }
9917 }
9918 }
9919 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009920#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009921 return nr;
9922}
9923
9924/*
9925 * Refill the input buffer and return the next input character:
9926 *
9927 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009928 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9929 * or we are reading from a string so we can't refill the buffer,
9930 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009931 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009932 * 4) Process input up to the next newline, deleting nul characters.
9933 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009934//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9935#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009936static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009937static int
Eric Andersenc470f442003-07-28 09:56:35 +00009938preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009939{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009940 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009941 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009942
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009943 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009944#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009945 if (g_parsefile->left_in_line == -1
9946 && g_parsefile->strpush->ap
9947 && g_parsefile->next_to_pgetc[-1] != ' '
9948 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009949 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009950 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009951 return PEOA;
9952 }
Eric Andersen2870d962001-07-02 17:27:21 +00009953#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009954 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009955 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009956 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009957 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009958 * "pgetc" needs refilling.
9959 */
9960
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009961 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009962 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009963 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009964 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009965 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009966 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009967 /* even in failure keep left_in_line and next_to_pgetc
9968 * in lock step, for correct multi-layer pungetc.
9969 * left_in_line was decremented before preadbuffer(),
9970 * must inc next_to_pgetc: */
9971 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009972 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009973 }
Eric Andersencb57d552001-06-28 07:25:16 +00009974
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009975 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009976 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009977 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009978 again:
9979 more = preadfd();
9980 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009981 /* don't try reading again */
9982 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009983 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009984 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009985 return PEOF;
9986 }
9987 }
9988
Denis Vlasenko727752d2008-11-28 03:41:47 +00009989 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009990 * Set g_parsefile->left_in_line
9991 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009992 * NUL chars are deleted.
9993 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009994 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009995 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009996 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009997
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009998 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009999
Denis Vlasenko727752d2008-11-28 03:41:47 +000010000 c = *q;
10001 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010002 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010003 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010004 q++;
10005 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010006 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010007 break;
10008 }
Eric Andersencb57d552001-06-28 07:25:16 +000010009 }
10010
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010011 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010012 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
10013 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +000010014 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010015 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010016 }
10017 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010018 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +000010019
Eric Andersencb57d552001-06-28 07:25:16 +000010020 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +000010021 char save = *q;
10022 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010023 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +000010024 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +000010025 }
10026
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010027 pgetc_debug("preadbuffer at %d:%p'%s'",
10028 g_parsefile->left_in_line,
10029 g_parsefile->next_to_pgetc,
10030 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +010010031 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +000010032}
10033
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010034static void
10035nlprompt(void)
10036{
10037 g_parsefile->linno++;
10038 setprompt_if(doprompt, 2);
10039}
10040static void
10041nlnoprompt(void)
10042{
10043 g_parsefile->linno++;
10044 needprompt = doprompt;
10045}
10046
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010047static int
10048pgetc(void)
10049{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010050 int c;
10051
10052 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010053 g_parsefile->left_in_line,
10054 g_parsefile->next_to_pgetc,
10055 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010056 if (g_parsefile->unget)
10057 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010058
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010059 if (--g_parsefile->left_in_line >= 0)
10060 c = (signed char)*g_parsefile->next_to_pgetc++;
10061 else
10062 c = preadbuffer();
10063
10064 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10065 g_parsefile->lastc[0] = c;
10066
10067 return c;
10068}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010069
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010070#if ENABLE_ASH_ALIAS
10071static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010072pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010073{
10074 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010075 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010076 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010077 g_parsefile->left_in_line,
10078 g_parsefile->next_to_pgetc,
10079 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010080 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010081 } while (c == PEOA);
10082 return c;
10083}
10084#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010085# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010086#endif
10087
10088/*
10089 * Read a line from the script.
10090 */
10091static char *
10092pfgets(char *line, int len)
10093{
10094 char *p = line;
10095 int nleft = len;
10096 int c;
10097
10098 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010099 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010100 if (c == PEOF) {
10101 if (p == line)
10102 return NULL;
10103 break;
10104 }
10105 *p++ = c;
10106 if (c == '\n')
10107 break;
10108 }
10109 *p = '\0';
10110 return line;
10111}
10112
Eric Andersenc470f442003-07-28 09:56:35 +000010113/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010114 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010115 * PEOF may be pushed back.
10116 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010117static void
Eric Andersenc470f442003-07-28 09:56:35 +000010118pungetc(void)
10119{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010120 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010121}
10122
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010123/* This one eats backslash+newline */
10124static int
10125pgetc_eatbnl(void)
10126{
10127 int c;
10128
10129 while ((c = pgetc()) == '\\') {
10130 if (pgetc() != '\n') {
10131 pungetc();
10132 break;
10133 }
10134
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010135 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010136 }
10137
10138 return c;
10139}
10140
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010141/*
10142 * To handle the "." command, a stack of input files is used. Pushfile
10143 * adds a new entry to the stack and popfile restores the previous level.
10144 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010145static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010146pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010147{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010148 struct parsefile *pf;
10149
Denis Vlasenko597906c2008-02-20 16:38:54 +000010150 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010151 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010152 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010153 /*pf->strpush = NULL; - ckzalloc did it */
10154 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010155 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010156 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010157}
10158
10159static void
10160popfile(void)
10161{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010162 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010163
Denis Vlasenkob012b102007-02-19 22:43:01 +000010164 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010165 if (pf->pf_fd >= 0)
10166 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010167 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010168 while (pf->strpush)
10169 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010170 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010171 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010172 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010173}
10174
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010175/*
10176 * Return to top level.
10177 */
10178static void
10179popallfiles(void)
10180{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010181 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010182 popfile();
10183}
10184
10185/*
10186 * Close the file(s) that the shell is reading commands from. Called
10187 * after a fork is done.
10188 */
10189static void
10190closescript(void)
10191{
10192 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010193 if (g_parsefile->pf_fd > 0) {
10194 close(g_parsefile->pf_fd);
10195 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010196 }
10197}
10198
10199/*
10200 * Like setinputfile, but takes an open file descriptor. Call this with
10201 * interrupts off.
10202 */
10203static void
10204setinputfd(int fd, int push)
10205{
Denis Vlasenko96e1b382007-09-30 23:50:48 +000010206 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010207 if (push) {
10208 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010209 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010210 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010211 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010212 if (g_parsefile->buf == NULL)
10213 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010214 g_parsefile->left_in_buffer = 0;
10215 g_parsefile->left_in_line = 0;
10216 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010217}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010218
Eric Andersenc470f442003-07-28 09:56:35 +000010219/*
10220 * Set the input to take input from a file. If push is set, push the
10221 * old input onto the stack first.
10222 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010223static int
10224setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010225{
10226 int fd;
10227 int fd2;
10228
Denis Vlasenkob012b102007-02-19 22:43:01 +000010229 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010230 fd = open(fname, O_RDONLY);
10231 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010232 if (flags & INPUT_NOFILE_OK)
10233 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010234 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010235 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010236 }
Eric Andersenc470f442003-07-28 09:56:35 +000010237 if (fd < 10) {
10238 fd2 = copyfd(fd, 10);
10239 close(fd);
10240 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010241 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010242 fd = fd2;
10243 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010244 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010245 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010246 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010247 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010248}
10249
Eric Andersencb57d552001-06-28 07:25:16 +000010250/*
10251 * Like setinputfile, but takes input from a string.
10252 */
Eric Andersenc470f442003-07-28 09:56:35 +000010253static void
10254setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010255{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010256 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010257 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010258 g_parsefile->next_to_pgetc = string;
10259 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010260 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010261 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010262 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010263}
10264
10265
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010266/* ============ mail.c
10267 *
10268 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010269 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010270
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010271#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010272
Denys Vlasenko23841622015-10-09 15:52:03 +020010273/* Hash of mtimes of mailboxes */
10274static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010275/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010276static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010277
Eric Andersencb57d552001-06-28 07:25:16 +000010278/*
Eric Andersenc470f442003-07-28 09:56:35 +000010279 * Print appropriate message(s) if mail has arrived.
10280 * If mail_var_path_changed is set,
10281 * then the value of MAIL has mail_var_path_changed,
10282 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010283 */
Eric Andersenc470f442003-07-28 09:56:35 +000010284static void
10285chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010286{
Eric Andersencb57d552001-06-28 07:25:16 +000010287 const char *mpath;
10288 char *p;
10289 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010290 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010291 struct stackmark smark;
10292 struct stat statb;
10293
Eric Andersencb57d552001-06-28 07:25:16 +000010294 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010295 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010296 new_hash = 0;
10297 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010298 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010299 if (p == NULL)
10300 break;
10301 if (*p == '\0')
10302 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010303 for (q = p; *q; q++)
10304 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010305#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010306 if (q[-1] != '/')
10307 abort();
10308#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010309 q[-1] = '\0'; /* delete trailing '/' */
10310 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010311 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010312 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010313 /* Very simplistic "hash": just a sum of all mtimes */
10314 new_hash += (unsigned)statb.st_mtime;
10315 }
10316 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010317 if (mailtime_hash != 0)
10318 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010319 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010320 }
Eric Andersenc470f442003-07-28 09:56:35 +000010321 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010322 popstackmark(&smark);
10323}
Eric Andersencb57d552001-06-28 07:25:16 +000010324
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010325static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010326changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010327{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010328 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010329}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010330
Denis Vlasenko131ae172007-02-18 13:00:19 +000010331#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010332
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010333
10334/* ============ ??? */
10335
Eric Andersencb57d552001-06-28 07:25:16 +000010336/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010337 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010338 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010339static void
10340setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010341{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010342 char **newparam;
10343 char **ap;
10344 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010345
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010346 for (nparam = 0; argv[nparam]; nparam++)
10347 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010348 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10349 while (*argv) {
10350 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010351 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010352 *ap = NULL;
10353 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010354 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010355 shellparam.nparam = nparam;
10356 shellparam.p = newparam;
10357#if ENABLE_ASH_GETOPTS
10358 shellparam.optind = 1;
10359 shellparam.optoff = -1;
10360#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010361}
10362
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010363/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010364 * Process shell options. The global variable argptr contains a pointer
10365 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010366 *
10367 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10368 * For a non-interactive shell, an error condition encountered
10369 * by a special built-in ... shall cause the shell to write a diagnostic message
10370 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010371 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010372 * ...
10373 * Utility syntax error (option or operand error) Shall exit
10374 * ...
10375 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10376 * we see that bash does not do that (set "finishes" with error code 1 instead,
10377 * and shell continues), and people rely on this behavior!
10378 * Testcase:
10379 * set -o barfoo 2>/dev/null
10380 * echo $?
10381 *
10382 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010383 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010384static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010385plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010386{
10387 int i;
10388
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010389 if (name) {
10390 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010391 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010392 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010393 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010394 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010395 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010396 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010397 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010398 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010399 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010400 if (val) {
10401 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10402 } else {
10403 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10404 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010405 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010406 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010407}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010408static void
10409setoption(int flag, int val)
10410{
10411 int i;
10412
10413 for (i = 0; i < NOPTS; i++) {
10414 if (optletters(i) == flag) {
10415 optlist[i] = val;
10416 return;
10417 }
10418 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010419 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010420 /* NOTREACHED */
10421}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010422static int
Eric Andersenc470f442003-07-28 09:56:35 +000010423options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010424{
10425 char *p;
10426 int val;
10427 int c;
10428
10429 if (cmdline)
10430 minusc = NULL;
10431 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010432 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010433 if (c != '-' && c != '+')
10434 break;
10435 argptr++;
10436 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010437 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010438 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010439 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010440 if (!cmdline) {
10441 /* "-" means turn off -x and -v */
10442 if (p[0] == '\0')
10443 xflag = vflag = 0;
10444 /* "--" means reset params */
10445 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010446 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010447 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010448 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010449 }
Eric Andersencb57d552001-06-28 07:25:16 +000010450 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010451 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010452 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010453 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010454 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010455 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010456 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010457 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010458 /* it already printed err message */
10459 return 1; /* error */
10460 }
Eric Andersencb57d552001-06-28 07:25:16 +000010461 if (*argptr)
10462 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010463 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10464 isloginsh = 1;
10465 /* bash does not accept +-login, we also won't */
10466 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010467 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010468 isloginsh = 1;
10469 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010470 } else {
10471 setoption(c, val);
10472 }
10473 }
10474 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010475 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010476}
10477
Eric Andersencb57d552001-06-28 07:25:16 +000010478/*
Eric Andersencb57d552001-06-28 07:25:16 +000010479 * The shift builtin command.
10480 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010481static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010482shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010483{
10484 int n;
10485 char **ap1, **ap2;
10486
10487 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010488 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010489 n = number(argv[1]);
10490 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010491 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010492 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010493 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010494 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010495 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010496 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010497 }
10498 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010499 while ((*ap2++ = *ap1++) != NULL)
10500 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010501#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010502 shellparam.optind = 1;
10503 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010504#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010505 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010506 return 0;
10507}
10508
Eric Andersencb57d552001-06-28 07:25:16 +000010509/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010510 * POSIX requires that 'set' (but not export or readonly) output the
10511 * variables in lexicographic order - by the locale's collating order (sigh).
10512 * Maybe we could keep them in an ordered balanced binary tree
10513 * instead of hashed lists.
10514 * For now just roll 'em through qsort for printing...
10515 */
10516static int
10517showvars(const char *sep_prefix, int on, int off)
10518{
10519 const char *sep;
10520 char **ep, **epend;
10521
10522 ep = listvars(on, off, &epend);
10523 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10524
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010525 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010526
10527 for (; ep < epend; ep++) {
10528 const char *p;
10529 const char *q;
10530
10531 p = strchrnul(*ep, '=');
10532 q = nullstr;
10533 if (*p)
10534 q = single_quote(++p);
10535 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10536 }
10537 return 0;
10538}
10539
10540/*
Eric Andersencb57d552001-06-28 07:25:16 +000010541 * The set command builtin.
10542 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010543static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010544setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010545{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010546 int retval;
10547
Denis Vlasenko68404f12008-03-17 09:00:54 +000010548 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010549 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010550
Denis Vlasenkob012b102007-02-19 22:43:01 +000010551 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010552 retval = options(/*cmdline:*/ 0);
10553 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010554 optschanged();
10555 if (*argptr != NULL) {
10556 setparam(argptr);
10557 }
Eric Andersencb57d552001-06-28 07:25:16 +000010558 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010559 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010560 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010561}
10562
Denis Vlasenko131ae172007-02-18 13:00:19 +000010563#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010564static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010565change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010566{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010567 uint32_t t;
10568
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010569 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010570 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010571 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010572 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010573 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010574 vrandom.flags &= ~VNOFUNC;
10575 } else {
10576 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010577 t = strtoul(value, NULL, 10);
10578 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010579 }
Eric Andersenef02f822004-03-11 13:34:24 +000010580}
Eric Andersen16767e22004-03-16 05:14:10 +000010581#endif
10582
Denis Vlasenko131ae172007-02-18 13:00:19 +000010583#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010584static int
Eric Andersenc470f442003-07-28 09:56:35 +000010585getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010586{
10587 char *p, *q;
10588 char c = '?';
10589 int done = 0;
10590 int err = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010591 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010592 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010593
Denys Vlasenko9c541002015-10-07 15:44:36 +020010594 sbuf[1] = '\0';
10595
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010596 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010597 return 1;
10598 optnext = optfirst + *param_optind - 1;
10599
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010600 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010601 p = NULL;
10602 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010603 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010604 if (p == NULL || *p == '\0') {
10605 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010606 p = *optnext;
10607 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010608 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010609 p = NULL;
10610 done = 1;
10611 goto out;
10612 }
10613 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010614 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010615 goto atend;
10616 }
10617
10618 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010619 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010620 if (*q == '\0') {
10621 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010622 sbuf[0] = c;
10623 /*sbuf[1] = '\0'; - already is */
10624 err |= setvarsafe("OPTARG", sbuf, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010625 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010626 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010627 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010628 }
10629 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010630 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010631 }
10632 if (*++q == ':')
10633 q++;
10634 }
10635
10636 if (*++q == ':') {
10637 if (*p == '\0' && (p = *optnext) == NULL) {
10638 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010639 sbuf[0] = c;
10640 /*sbuf[1] = '\0'; - already is */
10641 err |= setvarsafe("OPTARG", sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010642 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010643 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010644 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010645 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010646 c = '?';
10647 }
Eric Andersenc470f442003-07-28 09:56:35 +000010648 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010649 }
10650
10651 if (p == *optnext)
10652 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010653 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010654 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010655 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010656 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010657 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010658 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010659 *param_optind = optnext - optfirst + 1;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010660 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC);
10661 sbuf[0] = c;
10662 /*sbuf[1] = '\0'; - already is */
10663 err |= setvarsafe(optvar, sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010664 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010665 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010666 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010667 flush_stdout_stderr();
10668 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010669 }
10670 return done;
10671}
Eric Andersenc470f442003-07-28 09:56:35 +000010672
10673/*
10674 * The getopts builtin. Shellparam.optnext points to the next argument
10675 * to be processed. Shellparam.optptr points to the next character to
10676 * be processed in the current argument. If shellparam.optnext is NULL,
10677 * then it's the first time getopts has been called.
10678 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010679static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010680getoptscmd(int argc, char **argv)
10681{
10682 char **optbase;
10683
10684 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010685 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010686 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010687 optbase = shellparam.p;
10688 if (shellparam.optind > shellparam.nparam + 1) {
10689 shellparam.optind = 1;
10690 shellparam.optoff = -1;
10691 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010692 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010693 optbase = &argv[3];
10694 if (shellparam.optind > argc - 2) {
10695 shellparam.optind = 1;
10696 shellparam.optoff = -1;
10697 }
10698 }
10699
10700 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010701 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010702}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010703#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010704
Eric Andersencb57d552001-06-28 07:25:16 +000010705
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010706/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010707
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010708struct heredoc {
10709 struct heredoc *next; /* next here document in list */
10710 union node *here; /* redirection node */
10711 char *eofmark; /* string indicating end of input */
10712 smallint striptabs; /* if set, strip leading tabs */
10713};
10714
10715static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010716static smallint quoteflag; /* set if (part of) last token was quoted */
10717static token_id_t lasttoken; /* last token read (integer id Txxx) */
10718static struct heredoc *heredoclist; /* list of here documents to read */
10719static char *wordtext; /* text of last word returned by readtoken */
10720static struct nodelist *backquotelist;
10721static union node *redirnode;
10722static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010723
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010724static const char *
10725tokname(char *buf, int tok)
10726{
10727 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010728 return tokname_array[tok];
10729 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010730 return buf;
10731}
10732
10733/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010734 * Called when an unexpected token is read during the parse. The argument
10735 * is the token that is expected, or -1 if more than one type of token can
10736 * occur at this point.
10737 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010738static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010739static void
10740raise_error_unexpected_syntax(int token)
10741{
10742 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010743 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010744 int l;
10745
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010746 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010747 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010748 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010749 raise_error_syntax(msg);
10750 /* NOTREACHED */
10751}
Eric Andersencb57d552001-06-28 07:25:16 +000010752
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010753#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010754
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010755/* parsing is heavily cross-recursive, need these forward decls */
10756static union node *andor(void);
10757static union node *pipeline(void);
10758static union node *parse_command(void);
10759static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010760static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010761static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010762
Eric Andersenc470f442003-07-28 09:56:35 +000010763static union node *
10764list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010765{
10766 union node *n1, *n2, *n3;
10767 int tok;
10768
Eric Andersencb57d552001-06-28 07:25:16 +000010769 n1 = NULL;
10770 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010771 switch (peektoken()) {
10772 case TNL:
10773 if (!(nlflag & 1))
10774 break;
10775 parseheredoc();
10776 return n1;
10777
10778 case TEOF:
10779 if (!n1 && (nlflag & 1))
10780 n1 = NODE_EOF;
10781 parseheredoc();
10782 return n1;
10783 }
10784
10785 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010786 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010787 return n1;
10788 nlflag |= 2;
10789
Eric Andersencb57d552001-06-28 07:25:16 +000010790 n2 = andor();
10791 tok = readtoken();
10792 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010793 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010794 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010795 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010796 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010797 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010798 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010799 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010800 n2 = n3;
10801 }
10802 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010803 }
10804 }
10805 if (n1 == NULL) {
10806 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010807 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010808 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010809 n3->type = NSEMI;
10810 n3->nbinary.ch1 = n1;
10811 n3->nbinary.ch2 = n2;
10812 n1 = n3;
10813 }
10814 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010815 case TNL:
10816 case TEOF:
10817 tokpushback = 1;
10818 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010819 case TBACKGND:
10820 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010821 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010822 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010823 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010824 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010825 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010826 return n1;
10827 }
10828 }
10829}
10830
Eric Andersenc470f442003-07-28 09:56:35 +000010831static union node *
10832andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010833{
Eric Andersencb57d552001-06-28 07:25:16 +000010834 union node *n1, *n2, *n3;
10835 int t;
10836
Eric Andersencb57d552001-06-28 07:25:16 +000010837 n1 = pipeline();
10838 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010839 t = readtoken();
10840 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010841 t = NAND;
10842 } else if (t == TOR) {
10843 t = NOR;
10844 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010845 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010846 return n1;
10847 }
Eric Andersenc470f442003-07-28 09:56:35 +000010848 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010849 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010850 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010851 n3->type = t;
10852 n3->nbinary.ch1 = n1;
10853 n3->nbinary.ch2 = n2;
10854 n1 = n3;
10855 }
10856}
10857
Eric Andersenc470f442003-07-28 09:56:35 +000010858static union node *
10859pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010860{
Eric Andersencb57d552001-06-28 07:25:16 +000010861 union node *n1, *n2, *pipenode;
10862 struct nodelist *lp, *prev;
10863 int negate;
10864
10865 negate = 0;
10866 TRACE(("pipeline: entered\n"));
10867 if (readtoken() == TNOT) {
10868 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010869 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010870 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010871 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010872 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010873 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010874 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010875 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010876 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010877 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010878 pipenode->npipe.cmdlist = lp;
10879 lp->n = n1;
10880 do {
10881 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010882 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010883 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010884 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010885 prev->next = lp;
10886 } while (readtoken() == TPIPE);
10887 lp->next = NULL;
10888 n1 = pipenode;
10889 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010890 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010891 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010892 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010893 n2->type = NNOT;
10894 n2->nnot.com = n1;
10895 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010896 }
10897 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010898}
10899
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010900static union node *
10901makename(void)
10902{
10903 union node *n;
10904
Denis Vlasenko597906c2008-02-20 16:38:54 +000010905 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010906 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010907 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010908 n->narg.text = wordtext;
10909 n->narg.backquote = backquotelist;
10910 return n;
10911}
10912
10913static void
10914fixredir(union node *n, const char *text, int err)
10915{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010916 int fd;
10917
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010918 TRACE(("Fix redir %s %d\n", text, err));
10919 if (!err)
10920 n->ndup.vname = NULL;
10921
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010922 fd = bb_strtou(text, NULL, 10);
10923 if (!errno && fd >= 0)
10924 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010925 else if (LONE_DASH(text))
10926 n->ndup.dupfd = -1;
10927 else {
10928 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010929 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010930 n->ndup.vname = makename();
10931 }
10932}
10933
10934/*
10935 * Returns true if the text contains nothing to expand (no dollar signs
10936 * or backquotes).
10937 */
10938static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010939noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010940{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010941 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010942
Denys Vlasenkocd716832009-11-28 22:14:02 +010010943 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010944 if (c == CTLQUOTEMARK)
10945 continue;
10946 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010947 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010948 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010949 return 0;
10950 }
10951 return 1;
10952}
10953
10954static void
10955parsefname(void)
10956{
10957 union node *n = redirnode;
10958
10959 if (readtoken() != TWORD)
10960 raise_error_unexpected_syntax(-1);
10961 if (n->type == NHERE) {
10962 struct heredoc *here = heredoc;
10963 struct heredoc *p;
10964 int i;
10965
10966 if (quoteflag == 0)
10967 n->type = NXHERE;
10968 TRACE(("Here document %d\n", n->type));
10969 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010970 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010971 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010972 here->eofmark = wordtext;
10973 here->next = NULL;
10974 if (heredoclist == NULL)
10975 heredoclist = here;
10976 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010977 for (p = heredoclist; p->next; p = p->next)
10978 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010979 p->next = here;
10980 }
10981 } else if (n->type == NTOFD || n->type == NFROMFD) {
10982 fixredir(n, wordtext, 0);
10983 } else {
10984 n->nfile.fname = makename();
10985 }
10986}
Eric Andersencb57d552001-06-28 07:25:16 +000010987
Eric Andersenc470f442003-07-28 09:56:35 +000010988static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010989simplecmd(void)
10990{
10991 union node *args, **app;
10992 union node *n = NULL;
10993 union node *vars, **vpp;
10994 union node **rpp, *redir;
10995 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010996#if ENABLE_ASH_BASH_COMPAT
10997 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000010998 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010999#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011000
11001 args = NULL;
11002 app = &args;
11003 vars = NULL;
11004 vpp = &vars;
11005 redir = NULL;
11006 rpp = &redir;
11007
11008 savecheckkwd = CHKALIAS;
11009 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000011010 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011011 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011012 t = readtoken();
11013 switch (t) {
11014#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000011015 case TFUNCTION:
11016 if (peektoken() != TWORD)
11017 raise_error_unexpected_syntax(TWORD);
11018 function_flag = 1;
11019 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011020 case TAND: /* "&&" */
11021 case TOR: /* "||" */
11022 if (!double_brackets_flag) {
11023 tokpushback = 1;
11024 goto out;
11025 }
11026 wordtext = (char *) (t == TAND ? "-a" : "-o");
11027#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011028 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011029 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011030 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011031 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011032 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000011033#if ENABLE_ASH_BASH_COMPAT
11034 if (strcmp("[[", wordtext) == 0)
11035 double_brackets_flag = 1;
11036 else if (strcmp("]]", wordtext) == 0)
11037 double_brackets_flag = 0;
11038#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011039 n->narg.backquote = backquotelist;
11040 if (savecheckkwd && isassignment(wordtext)) {
11041 *vpp = n;
11042 vpp = &n->narg.next;
11043 } else {
11044 *app = n;
11045 app = &n->narg.next;
11046 savecheckkwd = 0;
11047 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011048#if ENABLE_ASH_BASH_COMPAT
11049 if (function_flag) {
11050 checkkwd = CHKNL | CHKKWD;
11051 switch (peektoken()) {
11052 case TBEGIN:
11053 case TIF:
11054 case TCASE:
11055 case TUNTIL:
11056 case TWHILE:
11057 case TFOR:
11058 goto do_func;
11059 case TLP:
11060 function_flag = 0;
11061 break;
11062 case TWORD:
11063 if (strcmp("[[", wordtext) == 0)
11064 goto do_func;
11065 /* fall through */
11066 default:
11067 raise_error_unexpected_syntax(-1);
11068 }
11069 }
11070#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011071 break;
11072 case TREDIR:
11073 *rpp = n = redirnode;
11074 rpp = &n->nfile.next;
11075 parsefname(); /* read name of redirection file */
11076 break;
11077 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000011078 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011079 if (args && app == &args->narg.next
11080 && !vars && !redir
11081 ) {
11082 struct builtincmd *bcmd;
11083 const char *name;
11084
11085 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000011086 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011087 raise_error_unexpected_syntax(TRP);
11088 name = n->narg.text;
11089 if (!goodname(name)
11090 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11091 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011092 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011093 }
11094 n->type = NDEFUN;
11095 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11096 n->narg.next = parse_command();
11097 return n;
11098 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011099 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011100 /* fall through */
11101 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011102 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011103 goto out;
11104 }
11105 }
11106 out:
11107 *app = NULL;
11108 *vpp = NULL;
11109 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011110 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011111 n->type = NCMD;
11112 n->ncmd.args = args;
11113 n->ncmd.assign = vars;
11114 n->ncmd.redirect = redir;
11115 return n;
11116}
11117
11118static union node *
11119parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011120{
Eric Andersencb57d552001-06-28 07:25:16 +000011121 union node *n1, *n2;
11122 union node *ap, **app;
11123 union node *cp, **cpp;
11124 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011125 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011126 int t;
11127
11128 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011129 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011130
Eric Andersencb57d552001-06-28 07:25:16 +000011131 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011132 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011133 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011134 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011135 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011136 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011137 n1->type = NIF;
11138 n1->nif.test = list(0);
11139 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011140 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011141 n1->nif.ifpart = list(0);
11142 n2 = n1;
11143 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011144 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011145 n2 = n2->nif.elsepart;
11146 n2->type = NIF;
11147 n2->nif.test = list(0);
11148 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011149 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011150 n2->nif.ifpart = list(0);
11151 }
11152 if (lasttoken == TELSE)
11153 n2->nif.elsepart = list(0);
11154 else {
11155 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011156 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011157 }
Eric Andersenc470f442003-07-28 09:56:35 +000011158 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011159 break;
11160 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011161 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011162 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011163 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011164 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011165 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011166 got = readtoken();
11167 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011168 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011169 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011170 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011171 }
11172 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011173 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011174 break;
11175 }
11176 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011177 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011178 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011179 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011180 n1->type = NFOR;
11181 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011182 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011183 if (readtoken() == TIN) {
11184 app = &ap;
11185 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011186 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011187 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011188 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011189 n2->narg.text = wordtext;
11190 n2->narg.backquote = backquotelist;
11191 *app = n2;
11192 app = &n2->narg.next;
11193 }
11194 *app = NULL;
11195 n1->nfor.args = ap;
11196 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011197 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011198 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011199 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011200 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011201 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011202 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011203 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011204 n1->nfor.args = n2;
11205 /*
11206 * Newline or semicolon here is optional (but note
11207 * that the original Bourne shell only allowed NL).
11208 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011209 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011210 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011211 }
Eric Andersenc470f442003-07-28 09:56:35 +000011212 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011213 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011214 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011215 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011216 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011217 break;
11218 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011219 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011220 n1->type = NCASE;
11221 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011222 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011223 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011224 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011225 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011226 n2->narg.text = wordtext;
11227 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011228 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11229 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011230 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011231 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011232 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011233 checkkwd = CHKNL | CHKKWD;
11234 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011235 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011236 if (lasttoken == TLP)
11237 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011238 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011239 cp->type = NCLIST;
11240 app = &cp->nclist.pattern;
11241 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011242 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011243 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011244 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011245 ap->narg.text = wordtext;
11246 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011247 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011248 break;
11249 app = &ap->narg.next;
11250 readtoken();
11251 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011252 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011253 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011254 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011255 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011256
Eric Andersenc470f442003-07-28 09:56:35 +000011257 cpp = &cp->nclist.next;
11258
11259 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011260 t = readtoken();
11261 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011262 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011263 raise_error_unexpected_syntax(TENDCASE);
11264 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011265 }
Eric Andersenc470f442003-07-28 09:56:35 +000011266 }
Eric Andersencb57d552001-06-28 07:25:16 +000011267 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011268 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011269 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011270 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011271 n1->type = NSUBSHELL;
11272 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011273 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011274 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011275 break;
11276 case TBEGIN:
11277 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011278 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011279 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011280 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011281 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011282 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011283 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011284 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011285 }
11286
Eric Andersenc470f442003-07-28 09:56:35 +000011287 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011288 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011289
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011290 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011291 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011292 checkkwd = CHKKWD | CHKALIAS;
11293 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011294 while (readtoken() == TREDIR) {
11295 *rpp = n2 = redirnode;
11296 rpp = &n2->nfile.next;
11297 parsefname();
11298 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011299 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011300 *rpp = NULL;
11301 if (redir) {
11302 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011303 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011304 n2->type = NREDIR;
11305 n2->nredir.n = n1;
11306 n1 = n2;
11307 }
11308 n1->nredir.redirect = redir;
11309 }
Eric Andersencb57d552001-06-28 07:25:16 +000011310 return n1;
11311}
11312
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011313#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011314static int
11315decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011316{
11317 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11318 int c, cnt;
11319 char *p;
11320 char buf[4];
11321
11322 c = pgetc();
11323 p = strchr(C_escapes, c);
11324 if (p) {
11325 buf[0] = c;
11326 p = buf;
11327 cnt = 3;
11328 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11329 do {
11330 c = pgetc();
11331 *++p = c;
11332 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11333 pungetc();
11334 } else if (c == 'x') { /* \xHH */
11335 do {
11336 c = pgetc();
11337 *++p = c;
11338 } while (isxdigit(c) && --cnt);
11339 pungetc();
11340 if (cnt == 3) { /* \x but next char is "bad" */
11341 c = 'x';
11342 goto unrecognized;
11343 }
11344 } else { /* simple seq like \\ or \t */
11345 p++;
11346 }
11347 *p = '\0';
11348 p = buf;
11349 c = bb_process_escape_sequence((void*)&p);
11350 } else { /* unrecognized "\z": print both chars unless ' or " */
11351 if (c != '\'' && c != '"') {
11352 unrecognized:
11353 c |= 0x100; /* "please encode \, then me" */
11354 }
11355 }
11356 return c;
11357}
11358#endif
11359
Eric Andersencb57d552001-06-28 07:25:16 +000011360/*
11361 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11362 * is not NULL, read a here document. In the latter case, eofmark is the
11363 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011364 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011365 * is the first character of the input token or document.
11366 *
11367 * Because C does not have internal subroutines, I have simulated them
11368 * using goto's to implement the subroutine linkage. The following macros
11369 * will run code that appears at the end of readtoken1.
11370 */
Eric Andersen2870d962001-07-02 17:27:21 +000011371#define CHECKEND() {goto checkend; checkend_return:;}
11372#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11373#define PARSESUB() {goto parsesub; parsesub_return:;}
11374#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11375#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11376#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011377static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011378readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011379{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011380 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011381 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011382 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011383 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011384 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011385 struct nodelist *bqlist;
11386 smallint quotef;
11387 smallint dblquote;
11388 smallint oldstyle;
11389 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011390#if ENABLE_ASH_EXPAND_PRMT
11391 smallint pssyntax; /* we are expanding a prompt string */
11392#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011393 int varnest; /* levels of variables expansion */
11394 int arinest; /* levels of arithmetic expansion */
11395 int parenlevel; /* levels of parens in arithmetic */
11396 int dqvarnest; /* levels of variables expansion within double quotes */
11397
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011398 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011399
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011400 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011401 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011402 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011403 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011404#if ENABLE_ASH_EXPAND_PRMT
11405 pssyntax = (syntax == PSSYNTAX);
11406 if (pssyntax)
11407 syntax = DQSYNTAX;
11408#endif
11409 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011410 varnest = 0;
11411 arinest = 0;
11412 parenlevel = 0;
11413 dqvarnest = 0;
11414
11415 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011416 loop:
11417 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011418 CHECKEND(); /* set c to PEOF if at end of here document */
11419 for (;;) { /* until end of line or end of word */
11420 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11421 switch (SIT(c, syntax)) {
11422 case CNL: /* '\n' */
11423 if (syntax == BASESYNTAX)
11424 goto endword; /* exit outer loop */
11425 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011426 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011427 c = pgetc();
11428 goto loop; /* continue outer loop */
11429 case CWORD:
11430 USTPUTC(c, out);
11431 break;
11432 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011433#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011434 if (c == '\\' && bash_dollar_squote) {
11435 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011436 if (c == '\0') {
11437 /* skip $'\000', $'\x00' (like bash) */
11438 break;
11439 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011440 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011441 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011442 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011443 if (eofmark == NULL || dblquote)
11444 USTPUTC(CTLESC, out);
11445 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011446 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011447 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011448#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011449 if (eofmark == NULL || dblquote)
11450 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011451 USTPUTC(c, out);
11452 break;
11453 case CBACK: /* backslash */
11454 c = pgetc_without_PEOA();
11455 if (c == PEOF) {
11456 USTPUTC(CTLESC, out);
11457 USTPUTC('\\', out);
11458 pungetc();
11459 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011460 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011461 } else {
11462#if ENABLE_ASH_EXPAND_PRMT
11463 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011464 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011465 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011466 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011467#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011468 /* Backslash is retained if we are in "str" and next char isn't special */
11469 if (dblquote
11470 && c != '\\'
11471 && c != '`'
11472 && c != '$'
11473 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011474 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011475 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011476 }
Ron Yorston549deab2015-05-18 09:57:51 +020011477 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011478 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011479 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011480 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011481 break;
11482 case CSQUOTE:
11483 syntax = SQSYNTAX;
11484 quotemark:
11485 if (eofmark == NULL) {
11486 USTPUTC(CTLQUOTEMARK, out);
11487 }
11488 break;
11489 case CDQUOTE:
11490 syntax = DQSYNTAX;
11491 dblquote = 1;
11492 goto quotemark;
11493 case CENDQUOTE:
11494 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011495 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011496 USTPUTC(c, out);
11497 } else {
11498 if (dqvarnest == 0) {
11499 syntax = BASESYNTAX;
11500 dblquote = 0;
11501 }
11502 quotef = 1;
11503 goto quotemark;
11504 }
11505 break;
11506 case CVAR: /* '$' */
11507 PARSESUB(); /* parse substitution */
11508 break;
11509 case CENDVAR: /* '}' */
11510 if (varnest > 0) {
11511 varnest--;
11512 if (dqvarnest > 0) {
11513 dqvarnest--;
11514 }
11515 c = CTLENDVAR;
11516 }
11517 USTPUTC(c, out);
11518 break;
11519#if ENABLE_SH_MATH_SUPPORT
11520 case CLP: /* '(' in arithmetic */
11521 parenlevel++;
11522 USTPUTC(c, out);
11523 break;
11524 case CRP: /* ')' in arithmetic */
11525 if (parenlevel > 0) {
11526 parenlevel--;
11527 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011528 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011529 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011530 if (--arinest == 0) {
11531 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011532 }
11533 } else {
11534 /*
11535 * unbalanced parens
11536 * (don't 2nd guess - no error)
11537 */
11538 pungetc();
11539 }
11540 }
11541 USTPUTC(c, out);
11542 break;
11543#endif
11544 case CBQUOTE: /* '`' */
11545 PARSEBACKQOLD();
11546 break;
11547 case CENDFILE:
11548 goto endword; /* exit outer loop */
11549 case CIGN:
11550 break;
11551 default:
11552 if (varnest == 0) {
11553#if ENABLE_ASH_BASH_COMPAT
11554 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011555//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011556 if (pgetc() == '>')
11557 c = 0x100 + '>'; /* flag &> */
11558 pungetc();
11559 }
11560#endif
11561 goto endword; /* exit outer loop */
11562 }
11563 IF_ASH_ALIAS(if (c != PEOA))
11564 USTPUTC(c, out);
11565 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011566 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011567 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011568 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011569
Mike Frysinger98c52642009-04-02 10:02:37 +000011570#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011571 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011572 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011573#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011574 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011575 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011576 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011577 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011578 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011579 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011580 }
11581 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011582 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011583 out = stackblock();
11584 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011585 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011586 && quotef == 0
11587 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011588 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011589 PARSEREDIR(); /* passed as params: out, c */
11590 lasttoken = TREDIR;
11591 return lasttoken;
11592 }
11593 /* else: non-number X seen, interpret it
11594 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011595 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011596 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011597 }
11598 quoteflag = quotef;
11599 backquotelist = bqlist;
11600 grabstackblock(len);
11601 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011602 lasttoken = TWORD;
11603 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011604/* end of readtoken routine */
11605
Eric Andersencb57d552001-06-28 07:25:16 +000011606/*
11607 * Check to see whether we are at the end of the here document. When this
11608 * is called, c is set to the first character of the next input line. If
11609 * we are at the end of the here document, this routine sets the c to PEOF.
11610 */
Eric Andersenc470f442003-07-28 09:56:35 +000011611checkend: {
11612 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011613#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011614 if (c == PEOA)
11615 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011616#endif
11617 if (striptabs) {
11618 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011619 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011620 }
Eric Andersenc470f442003-07-28 09:56:35 +000011621 }
11622 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011623 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011624 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011625
Eric Andersenc470f442003-07-28 09:56:35 +000011626 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011627 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11628 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011629 if (*p == '\n' && *q == '\0') {
11630 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011631 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011632 } else {
11633 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011634 }
11635 }
11636 }
11637 }
Eric Andersenc470f442003-07-28 09:56:35 +000011638 goto checkend_return;
11639}
Eric Andersencb57d552001-06-28 07:25:16 +000011640
Eric Andersencb57d552001-06-28 07:25:16 +000011641/*
11642 * Parse a redirection operator. The variable "out" points to a string
11643 * specifying the fd to be redirected. The variable "c" contains the
11644 * first character of the redirection operator.
11645 */
Eric Andersenc470f442003-07-28 09:56:35 +000011646parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011647 /* out is already checked to be a valid number or "" */
11648 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011649 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011650
Denis Vlasenko597906c2008-02-20 16:38:54 +000011651 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011652 if (c == '>') {
11653 np->nfile.fd = 1;
11654 c = pgetc();
11655 if (c == '>')
11656 np->type = NAPPEND;
11657 else if (c == '|')
11658 np->type = NCLOBBER;
11659 else if (c == '&')
11660 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011661 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011662 else {
11663 np->type = NTO;
11664 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011665 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011666 }
11667#if ENABLE_ASH_BASH_COMPAT
11668 else if (c == 0x100 + '>') { /* this flags &> redirection */
11669 np->nfile.fd = 1;
11670 pgetc(); /* this is '>', no need to check */
11671 np->type = NTO2;
11672 }
11673#endif
11674 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011675 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011676 c = pgetc();
11677 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011678 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011679 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011680 np = stzalloc(sizeof(struct nhere));
11681 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011682 }
11683 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011684 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011685 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011686 c = pgetc();
11687 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011688 heredoc->striptabs = 1;
11689 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011690 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011691 pungetc();
11692 }
11693 break;
11694
11695 case '&':
11696 np->type = NFROMFD;
11697 break;
11698
11699 case '>':
11700 np->type = NFROMTO;
11701 break;
11702
11703 default:
11704 np->type = NFROM;
11705 pungetc();
11706 break;
11707 }
Eric Andersencb57d552001-06-28 07:25:16 +000011708 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011709 if (fd >= 0)
11710 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011711 redirnode = np;
11712 goto parseredir_return;
11713}
Eric Andersencb57d552001-06-28 07:25:16 +000011714
Eric Andersencb57d552001-06-28 07:25:16 +000011715/*
11716 * Parse a substitution. At this point, we have read the dollar sign
11717 * and nothing else.
11718 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011719
11720/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11721 * (assuming ascii char codes, as the original implementation did) */
11722#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011723 (((unsigned)(c) - 33 < 32) \
11724 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011725parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011726 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011727 int typeloc;
11728 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011729
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011730 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011731 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011732 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011733 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011734#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011735 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011736 bash_dollar_squote = 1;
11737 else
11738#endif
11739 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011740 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011741 } else if (c == '(') {
11742 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011743 if (pgetc_eatbnl() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011744#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011745 PARSEARITH();
11746#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011747 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011748#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011749 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011750 pungetc();
11751 PARSEBACKQNEW();
11752 }
11753 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011754 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011755 USTPUTC(CTLVAR, out);
11756 typeloc = out - (char *)stackblock();
11757 USTPUTC(VSNORMAL, out);
11758 subtype = VSNORMAL;
11759 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011760 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000011761 if (c == '#') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011762 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011763 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011764 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011765 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011766 subtype = VSLENGTH; /* ${#VAR} */
11767 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011768 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011769 }
Eric Andersenc470f442003-07-28 09:56:35 +000011770 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011771 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011772 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011773 do {
11774 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011775 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011776 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011777 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011778 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011779 do {
11780 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011781 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011782 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011783 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011784 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011785 USTPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011786 c = pgetc_eatbnl();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011787 } else {
11788 badsub:
11789 raise_error_syntax("bad substitution");
11790 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011791 if (c != '}' && subtype == VSLENGTH) {
11792 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011793 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011794 }
Eric Andersencb57d552001-06-28 07:25:16 +000011795
Eric Andersenc470f442003-07-28 09:56:35 +000011796 STPUTC('=', out);
11797 flags = 0;
11798 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011799 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011800 /* ${VAR...} but not $VAR or ${#VAR} */
11801 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011802 switch (c) {
11803 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011804 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011805#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011806 /* This check is only needed to not misinterpret
11807 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11808 * constructs.
11809 */
11810 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011811 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011812 pungetc();
11813 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011814 }
11815#endif
11816 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011817 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011818 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011819 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011820 if (p == NULL)
11821 goto badsub;
11822 subtype = p - types + VSNORMAL;
11823 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011824 }
Eric Andersenc470f442003-07-28 09:56:35 +000011825 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011826 case '#': {
11827 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011828 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011829 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011830 if (c != cc)
11831 goto do_pungetc;
11832 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011833 break;
11834 }
11835#if ENABLE_ASH_BASH_COMPAT
11836 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011837 /* ${v/[/]pattern/repl} */
11838//TODO: encode pattern and repl separately.
11839// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011840 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011841 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011842 if (c != '/')
11843 goto do_pungetc;
11844 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011845 break;
11846#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011847 }
Eric Andersenc470f442003-07-28 09:56:35 +000011848 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011849 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011850 pungetc();
11851 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011852 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011853 if (subtype != VSNORMAL) {
11854 varnest++;
Ron Yorston7e4ed262015-05-18 09:54:43 +020011855 if (dblquote) {
Eric Andersenc470f442003-07-28 09:56:35 +000011856 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011857 }
11858 }
11859 }
Eric Andersenc470f442003-07-28 09:56:35 +000011860 goto parsesub_return;
11861}
Eric Andersencb57d552001-06-28 07:25:16 +000011862
Eric Andersencb57d552001-06-28 07:25:16 +000011863/*
11864 * Called to parse command substitutions. Newstyle is set if the command
11865 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11866 * list of commands (passed by reference), and savelen is the number of
11867 * characters on the top of the stack which must be preserved.
11868 */
Eric Andersenc470f442003-07-28 09:56:35 +000011869parsebackq: {
11870 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011871 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011872 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011873 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011874 smallint saveprompt = 0;
11875
Eric Andersenc470f442003-07-28 09:56:35 +000011876 str = NULL;
11877 savelen = out - (char *)stackblock();
11878 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011879 /*
11880 * FIXME: this can allocate very large block on stack and SEGV.
11881 * Example:
11882 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011883 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011884 * a hundred command substitutions stack overflows.
11885 * With larger prepended string, SEGV happens sooner.
11886 */
Ron Yorston072fc602015-07-01 16:46:18 +010011887 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011888 memcpy(str, stackblock(), savelen);
11889 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011890
Eric Andersenc470f442003-07-28 09:56:35 +000011891 if (oldstyle) {
11892 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011893 * treatment to some slashes, and then push the string and
11894 * reread it as input, interpreting it normally.
11895 */
Eric Andersenc470f442003-07-28 09:56:35 +000011896 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011897 size_t psavelen;
11898 char *pstr;
11899
Eric Andersenc470f442003-07-28 09:56:35 +000011900 STARTSTACKSTR(pout);
11901 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011902 int pc;
11903
11904 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011905 pc = pgetc();
11906 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011907 case '`':
11908 goto done;
11909
11910 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011911 pc = pgetc();
11912 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011913 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011914 /*
11915 * If eating a newline, avoid putting
11916 * the newline into the new character
11917 * stream (via the STPUTC after the
11918 * switch).
11919 */
11920 continue;
11921 }
11922 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011923 && (!dblquote || pc != '"')
11924 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011925 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011926 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011927 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011928 break;
11929 }
11930 /* fall through */
11931
11932 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011933 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011934 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011935 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011936
11937 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011938 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011939 break;
11940
11941 default:
11942 break;
11943 }
11944 STPUTC(pc, pout);
11945 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011946 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011947 STPUTC('\0', pout);
11948 psavelen = pout - (char *)stackblock();
11949 if (psavelen > 0) {
11950 pstr = grabstackstr(pout);
11951 setinputstring(pstr);
11952 }
11953 }
11954 nlpp = &bqlist;
11955 while (*nlpp)
11956 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011957 *nlpp = stzalloc(sizeof(**nlpp));
11958 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011959
11960 if (oldstyle) {
11961 saveprompt = doprompt;
11962 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011963 }
11964
Eric Andersenc470f442003-07-28 09:56:35 +000011965 n = list(2);
11966
11967 if (oldstyle)
11968 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011969 else if (readtoken() != TRP)
11970 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011971
11972 (*nlpp)->n = n;
11973 if (oldstyle) {
11974 /*
11975 * Start reading from old file again, ignoring any pushed back
11976 * tokens left from the backquote parsing
11977 */
11978 popfile();
11979 tokpushback = 0;
11980 }
11981 while (stackblocksize() <= savelen)
11982 growstackblock();
11983 STARTSTACKSTR(out);
11984 if (str) {
11985 memcpy(out, str, savelen);
11986 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011987 }
Ron Yorston549deab2015-05-18 09:57:51 +020011988 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011989 if (oldstyle)
11990 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011991 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011992}
11993
Mike Frysinger98c52642009-04-02 10:02:37 +000011994#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011995/*
11996 * Parse an arithmetic expansion (indicate start of one and set state)
11997 */
Eric Andersenc470f442003-07-28 09:56:35 +000011998parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011999 if (++arinest == 1) {
12000 prevsyntax = syntax;
12001 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000012002 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020012003 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000012004 goto parsearith_return;
12005}
12006#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012007} /* end of readtoken */
12008
Eric Andersencb57d552001-06-28 07:25:16 +000012009/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012010 * Read the next input token.
12011 * If the token is a word, we set backquotelist to the list of cmds in
12012 * backquotes. We set quoteflag to true if any part of the word was
12013 * quoted.
12014 * If the token is TREDIR, then we set redirnode to a structure containing
12015 * the redirection.
12016 * In all cases, the variable startlinno is set to the number of the line
12017 * on which the token starts.
12018 *
12019 * [Change comment: here documents and internal procedures]
12020 * [Readtoken shouldn't have any arguments. Perhaps we should make the
12021 * word parsing code into a separate routine. In this case, readtoken
12022 * doesn't need to have any internal procedures, but parseword does.
12023 * We could also make parseoperator in essence the main routine, and
12024 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000012025 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012026#define NEW_xxreadtoken
12027#ifdef NEW_xxreadtoken
12028/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012029static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000012030 '\n', '(', ')', /* singles */
12031 '&', '|', ';', /* doubles */
12032 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012033};
Eric Andersencb57d552001-06-28 07:25:16 +000012034
Denis Vlasenko834dee72008-10-07 09:18:30 +000012035#define xxreadtoken_singles 3
12036#define xxreadtoken_doubles 3
12037
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012038static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012039 TNL, TLP, TRP, /* only single occurrence allowed */
12040 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
12041 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012042 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012043};
12044
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012045static int
12046xxreadtoken(void)
12047{
12048 int c;
12049
12050 if (tokpushback) {
12051 tokpushback = 0;
12052 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012053 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012054 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012055 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012056 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012057 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012058 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012059 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012060
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012061 if (c == '#') {
12062 while ((c = pgetc()) != '\n' && c != PEOF)
12063 continue;
12064 pungetc();
12065 } else if (c == '\\') {
12066 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012067 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012068 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012069 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012070 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012071 } else {
12072 const char *p;
12073
12074 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12075 if (c != PEOF) {
12076 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012077 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012078 }
12079
12080 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012081 if (p == NULL)
12082 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012083
Denis Vlasenko834dee72008-10-07 09:18:30 +000012084 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12085 int cc = pgetc();
12086 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012087 p += xxreadtoken_doubles + 1;
12088 } else {
12089 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012090#if ENABLE_ASH_BASH_COMPAT
12091 if (c == '&' && cc == '>') /* &> */
12092 break; /* return readtoken1(...) */
12093#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012094 }
12095 }
12096 }
12097 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12098 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012099 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012100 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012101
12102 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012103}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012104#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012105#define RETURN(token) return lasttoken = token
12106static int
12107xxreadtoken(void)
12108{
12109 int c;
12110
12111 if (tokpushback) {
12112 tokpushback = 0;
12113 return lasttoken;
12114 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012115 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012116 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012117 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012118 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012119 switch (c) {
12120 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012121 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012122 continue;
12123 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012124 while ((c = pgetc()) != '\n' && c != PEOF)
12125 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012126 pungetc();
12127 continue;
12128 case '\\':
12129 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012130 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012131 continue;
12132 }
12133 pungetc();
12134 goto breakloop;
12135 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012136 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012137 RETURN(TNL);
12138 case PEOF:
12139 RETURN(TEOF);
12140 case '&':
12141 if (pgetc() == '&')
12142 RETURN(TAND);
12143 pungetc();
12144 RETURN(TBACKGND);
12145 case '|':
12146 if (pgetc() == '|')
12147 RETURN(TOR);
12148 pungetc();
12149 RETURN(TPIPE);
12150 case ';':
12151 if (pgetc() == ';')
12152 RETURN(TENDCASE);
12153 pungetc();
12154 RETURN(TSEMI);
12155 case '(':
12156 RETURN(TLP);
12157 case ')':
12158 RETURN(TRP);
12159 default:
12160 goto breakloop;
12161 }
12162 }
12163 breakloop:
12164 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12165#undef RETURN
12166}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012167#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012168
12169static int
12170readtoken(void)
12171{
12172 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012173 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012174#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012175 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012176#endif
12177
12178#if ENABLE_ASH_ALIAS
12179 top:
12180#endif
12181
12182 t = xxreadtoken();
12183
12184 /*
12185 * eat newlines
12186 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012187 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012188 while (t == TNL) {
12189 parseheredoc();
12190 t = xxreadtoken();
12191 }
12192 }
12193
12194 if (t != TWORD || quoteflag) {
12195 goto out;
12196 }
12197
12198 /*
12199 * check for keywords
12200 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012201 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012202 const char *const *pp;
12203
12204 pp = findkwd(wordtext);
12205 if (pp) {
12206 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012207 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012208 goto out;
12209 }
12210 }
12211
12212 if (checkkwd & CHKALIAS) {
12213#if ENABLE_ASH_ALIAS
12214 struct alias *ap;
12215 ap = lookupalias(wordtext, 1);
12216 if (ap != NULL) {
12217 if (*ap->val) {
12218 pushstring(ap->val, ap);
12219 }
12220 goto top;
12221 }
12222#endif
12223 }
12224 out:
12225 checkkwd = 0;
12226#if DEBUG
12227 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012228 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012229 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012230 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012231#endif
12232 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012233}
12234
Ron Yorstonc0e00762015-10-29 11:30:55 +000012235static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012236peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012237{
12238 int t;
12239
12240 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012241 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012242 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012243}
Eric Andersencb57d552001-06-28 07:25:16 +000012244
12245/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012246 * Read and parse a command. Returns NODE_EOF on end of file.
12247 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012248 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012249static union node *
12250parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012251{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012252 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012253 checkkwd = 0;
12254 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012255 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012256 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012257 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012258 return list(1);
12259}
12260
12261/*
12262 * Input any here documents.
12263 */
12264static void
12265parseheredoc(void)
12266{
12267 struct heredoc *here;
12268 union node *n;
12269
12270 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012271 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012272
12273 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012274 setprompt_if(needprompt, 2);
12275 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012276 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012277 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012278 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012279 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012280 n->narg.text = wordtext;
12281 n->narg.backquote = backquotelist;
12282 here->here->nhere.doc = n;
12283 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012284 }
Eric Andersencb57d552001-06-28 07:25:16 +000012285}
12286
12287
12288/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012289 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012290 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012291#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012292static const char *
12293expandstr(const char *ps)
12294{
12295 union node n;
12296
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012297 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12298 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012299 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012300 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"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{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012319 union node *n;
12320 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012321 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012322
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012323 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012324 setinputstring(s);
12325 setstackmark(&smark);
12326
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012327 status = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012328 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012329 int i;
12330
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012331 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012332 if (n)
12333 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012334 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012335 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012336 break;
12337 }
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012338 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012339 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012340 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012341
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012342 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012343}
12344
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012345/*
12346 * The eval command.
12347 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012348static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012349evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012350{
12351 char *p;
12352 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012353
Denis Vlasenko68404f12008-03-17 09:00:54 +000012354 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012355 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012356 argv += 2;
12357 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012358 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012359 for (;;) {
12360 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012361 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012362 if (p == NULL)
12363 break;
12364 STPUTC(' ', concat);
12365 }
12366 STPUTC('\0', concat);
12367 p = grabstackstr(concat);
12368 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012369 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012370 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012371 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012372}
12373
12374/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012375 * Read and execute commands.
12376 * "Top" is nonzero for the top level command loop;
12377 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012378 */
12379static int
12380cmdloop(int top)
12381{
12382 union node *n;
12383 struct stackmark smark;
12384 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012385 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012386 int numeof = 0;
12387
12388 TRACE(("cmdloop(%d) called\n", top));
12389 for (;;) {
12390 int skip;
12391
12392 setstackmark(&smark);
12393#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012394 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012395 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012396#endif
12397 inter = 0;
12398 if (iflag && top) {
12399 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012400 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012401 }
12402 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012403#if DEBUG
12404 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012405 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012406#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012407 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012408 if (!top || numeof >= 50)
12409 break;
12410 if (!stoppedjobs()) {
12411 if (!Iflag)
12412 break;
12413 out2str("\nUse \"exit\" to leave shell.\n");
12414 }
12415 numeof++;
12416 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012417 int i;
12418
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012419 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12420 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012421 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012422 i = evaltree(n, 0);
12423 if (n)
12424 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012425 }
12426 popstackmark(&smark);
12427 skip = evalskip;
12428
12429 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012430 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012431 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012432 }
12433 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012434 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012435}
12436
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012437/*
12438 * Take commands from a file. To be compatible we should do a path
12439 * search for the file, which is necessary to find sub-commands.
12440 */
12441static char *
12442find_dot_file(char *name)
12443{
12444 char *fullname;
12445 const char *path = pathval();
12446 struct stat statb;
12447
12448 /* don't try this for absolute or relative paths */
12449 if (strchr(name, '/'))
12450 return name;
12451
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012452 /* IIRC standards do not say whether . is to be searched.
12453 * And it is even smaller this way, making it unconditional for now:
12454 */
12455 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12456 fullname = name;
12457 goto try_cur_dir;
12458 }
12459
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012460 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012461 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012462 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12463 /*
12464 * Don't bother freeing here, since it will
12465 * be freed by the caller.
12466 */
12467 return fullname;
12468 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012469 if (fullname != name)
12470 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012471 }
12472
12473 /* not found in the PATH */
12474 ash_msg_and_raise_error("%s: not found", name);
12475 /* NOTREACHED */
12476}
12477
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012478static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012479dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012480{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012481 /* "false; . empty_file; echo $?" should print 0, not 1: */
12482 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012483 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012484 char **argv;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012485 struct strlist *sp;
12486 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012487
12488 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012489 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012490
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012491 nextopt(nullstr); /* handle possible "--" */
12492 argv = argptr;
12493
12494 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012495 /* bash says: "bash: .: filename argument required" */
12496 return 2; /* bash compat */
12497 }
12498
Denys Vlasenko091f8312013-03-17 14:25:22 +010012499 /* This aborts if file isn't found, which is POSIXly correct.
12500 * bash returns exitcode 1 instead.
12501 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012502 fullname = find_dot_file(argv[0]);
12503 argv++;
12504 if (argv[0]) { /* . FILE ARGS, ARGS exist */
12505 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012506 saveparam = shellparam;
12507 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012508 argc = 1;
12509 while (argv[argc])
12510 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012511 shellparam.nparam = argc;
12512 shellparam.p = argv;
12513 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012514
Denys Vlasenko091f8312013-03-17 14:25:22 +010012515 /* This aborts if file can't be opened, which is POSIXly correct.
12516 * bash returns exitcode 1 instead.
12517 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012518 setinputfile(fullname, INPUT_PUSH_FILE);
12519 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012520 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012521 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012522
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012523 if (argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012524 freeparam(&shellparam);
12525 shellparam = saveparam;
12526 };
12527
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012528 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012529}
12530
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012531static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012532exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012533{
12534 if (stoppedjobs())
12535 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012536 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012537 exitstatus = number(argv[1]);
12538 raise_exception(EXEXIT);
12539 /* NOTREACHED */
12540}
12541
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012542/*
12543 * Read a file containing shell functions.
12544 */
12545static void
12546readcmdfile(char *name)
12547{
12548 setinputfile(name, INPUT_PUSH_FILE);
12549 cmdloop(0);
12550 popfile();
12551}
12552
12553
Denis Vlasenkocc571512007-02-23 21:10:35 +000012554/* ============ find_command inplementation */
12555
12556/*
12557 * Resolve a command name. If you change this routine, you may have to
12558 * change the shellexec routine as well.
12559 */
12560static void
12561find_command(char *name, struct cmdentry *entry, int act, const char *path)
12562{
12563 struct tblentry *cmdp;
12564 int idx;
12565 int prev;
12566 char *fullname;
12567 struct stat statb;
12568 int e;
12569 int updatetbl;
12570 struct builtincmd *bcmd;
12571
12572 /* If name contains a slash, don't use PATH or hash table */
12573 if (strchr(name, '/') != NULL) {
12574 entry->u.index = -1;
12575 if (act & DO_ABS) {
12576 while (stat(name, &statb) < 0) {
12577#ifdef SYSV
12578 if (errno == EINTR)
12579 continue;
12580#endif
12581 entry->cmdtype = CMDUNKNOWN;
12582 return;
12583 }
12584 }
12585 entry->cmdtype = CMDNORMAL;
12586 return;
12587 }
12588
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012589/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012590
12591 updatetbl = (path == pathval());
12592 if (!updatetbl) {
12593 act |= DO_ALTPATH;
12594 if (strstr(path, "%builtin") != NULL)
12595 act |= DO_ALTBLTIN;
12596 }
12597
12598 /* If name is in the table, check answer will be ok */
12599 cmdp = cmdlookup(name, 0);
12600 if (cmdp != NULL) {
12601 int bit;
12602
12603 switch (cmdp->cmdtype) {
12604 default:
12605#if DEBUG
12606 abort();
12607#endif
12608 case CMDNORMAL:
12609 bit = DO_ALTPATH;
12610 break;
12611 case CMDFUNCTION:
12612 bit = DO_NOFUNC;
12613 break;
12614 case CMDBUILTIN:
12615 bit = DO_ALTBLTIN;
12616 break;
12617 }
12618 if (act & bit) {
12619 updatetbl = 0;
12620 cmdp = NULL;
12621 } else if (cmdp->rehash == 0)
12622 /* if not invalidated by cd, we're done */
12623 goto success;
12624 }
12625
12626 /* If %builtin not in path, check for builtin next */
12627 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012628 if (bcmd) {
12629 if (IS_BUILTIN_REGULAR(bcmd))
12630 goto builtin_success;
12631 if (act & DO_ALTPATH) {
12632 if (!(act & DO_ALTBLTIN))
12633 goto builtin_success;
12634 } else if (builtinloc <= 0) {
12635 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012636 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012637 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012638
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012639#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012640 {
12641 int applet_no = find_applet_by_name(name);
12642 if (applet_no >= 0) {
12643 entry->cmdtype = CMDNORMAL;
12644 entry->u.index = -2 - applet_no;
12645 return;
12646 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012647 }
12648#endif
12649
Denis Vlasenkocc571512007-02-23 21:10:35 +000012650 /* We have to search path. */
12651 prev = -1; /* where to start */
12652 if (cmdp && cmdp->rehash) { /* doing a rehash */
12653 if (cmdp->cmdtype == CMDBUILTIN)
12654 prev = builtinloc;
12655 else
12656 prev = cmdp->param.index;
12657 }
12658
12659 e = ENOENT;
12660 idx = -1;
12661 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012662 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012663 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012664 /* NB: code below will still use fullname
12665 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012666 idx++;
12667 if (pathopt) {
12668 if (prefix(pathopt, "builtin")) {
12669 if (bcmd)
12670 goto builtin_success;
12671 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012672 }
12673 if ((act & DO_NOFUNC)
12674 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012675 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012676 continue;
12677 }
12678 }
12679 /* if rehash, don't redo absolute path names */
12680 if (fullname[0] == '/' && idx <= prev) {
12681 if (idx < prev)
12682 continue;
12683 TRACE(("searchexec \"%s\": no change\n", name));
12684 goto success;
12685 }
12686 while (stat(fullname, &statb) < 0) {
12687#ifdef SYSV
12688 if (errno == EINTR)
12689 continue;
12690#endif
12691 if (errno != ENOENT && errno != ENOTDIR)
12692 e = errno;
12693 goto loop;
12694 }
12695 e = EACCES; /* if we fail, this will be the error */
12696 if (!S_ISREG(statb.st_mode))
12697 continue;
12698 if (pathopt) { /* this is a %func directory */
12699 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012700 /* NB: stalloc will return space pointed by fullname
12701 * (because we don't have any intervening allocations
12702 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012703 readcmdfile(fullname);
12704 cmdp = cmdlookup(name, 0);
12705 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12706 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12707 stunalloc(fullname);
12708 goto success;
12709 }
12710 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12711 if (!updatetbl) {
12712 entry->cmdtype = CMDNORMAL;
12713 entry->u.index = idx;
12714 return;
12715 }
12716 INT_OFF;
12717 cmdp = cmdlookup(name, 1);
12718 cmdp->cmdtype = CMDNORMAL;
12719 cmdp->param.index = idx;
12720 INT_ON;
12721 goto success;
12722 }
12723
12724 /* We failed. If there was an entry for this command, delete it */
12725 if (cmdp && updatetbl)
12726 delete_cmd_entry();
12727 if (act & DO_ERR)
12728 ash_msg("%s: %s", name, errmsg(e, "not found"));
12729 entry->cmdtype = CMDUNKNOWN;
12730 return;
12731
12732 builtin_success:
12733 if (!updatetbl) {
12734 entry->cmdtype = CMDBUILTIN;
12735 entry->u.cmd = bcmd;
12736 return;
12737 }
12738 INT_OFF;
12739 cmdp = cmdlookup(name, 1);
12740 cmdp->cmdtype = CMDBUILTIN;
12741 cmdp->param.cmd = bcmd;
12742 INT_ON;
12743 success:
12744 cmdp->rehash = 0;
12745 entry->cmdtype = cmdp->cmdtype;
12746 entry->u = cmdp->param;
12747}
12748
12749
Eric Andersencb57d552001-06-28 07:25:16 +000012750/*
Eric Andersencb57d552001-06-28 07:25:16 +000012751 * The trap builtin.
12752 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012753static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012754trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012755{
12756 char *action;
12757 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012758 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012759
Eric Andersenc470f442003-07-28 09:56:35 +000012760 nextopt(nullstr);
12761 ap = argptr;
12762 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012763 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012764 char *tr = trap_ptr[signo];
12765 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012766 /* note: bash adds "SIG", but only if invoked
12767 * as "bash". If called as "sh", or if set -o posix,
12768 * then it prints short signal names.
12769 * We are printing short names: */
12770 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012771 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012772 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012773 /* trap_ptr != trap only if we are in special-cased `trap` code.
12774 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012775 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012776 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012777 }
12778 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012779 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012780 if (trap_ptr != trap) {
12781 free(trap_ptr);
12782 trap_ptr = trap;
12783 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012784 */
Eric Andersencb57d552001-06-28 07:25:16 +000012785 return 0;
12786 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012787
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012788 action = NULL;
12789 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012790 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012791 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012792 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012793 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012794 if (signo < 0) {
12795 /* Mimic bash message exactly */
12796 ash_msg("%s: invalid signal specification", *ap);
12797 exitcode = 1;
12798 goto next;
12799 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012800 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012801 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012802 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012803 action = NULL;
12804 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012805 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012806 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012807 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012808 if (action)
12809 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012810 trap[signo] = action;
12811 if (signo != 0)
12812 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012813 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012814 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012815 ap++;
12816 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012817 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012818}
12819
Eric Andersenc470f442003-07-28 09:56:35 +000012820
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012821/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012822
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012823#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012824static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012825helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012826{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012827 unsigned col;
12828 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012829
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012830 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012831 "Built-in commands:\n"
12832 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012833 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012834 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012835 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012836 if (col > 60) {
12837 out1fmt("\n");
12838 col = 0;
12839 }
12840 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012841# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012842 {
12843 const char *a = applet_names;
12844 while (*a) {
12845 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12846 if (col > 60) {
12847 out1fmt("\n");
12848 col = 0;
12849 }
Ron Yorston2b919582016-04-08 11:57:20 +010012850 while (*a++ != '\0')
12851 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012852 }
12853 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012854# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020012855 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000012856 return EXIT_SUCCESS;
12857}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012858#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012859
Flemming Madsend96ffda2013-04-07 18:47:24 +020012860#if MAX_HISTORY
12861static int FAST_FUNC
12862historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12863{
12864 show_history(line_input_state);
12865 return EXIT_SUCCESS;
12866}
12867#endif
12868
Eric Andersencb57d552001-06-28 07:25:16 +000012869/*
Eric Andersencb57d552001-06-28 07:25:16 +000012870 * The export and readonly commands.
12871 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012872static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012873exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012874{
12875 struct var *vp;
12876 char *name;
12877 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012878 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012879 char opt;
12880 int flag;
12881 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012882
Denys Vlasenkod5275882012-10-01 13:41:17 +020012883 /* "readonly" in bash accepts, but ignores -n.
12884 * We do the same: it saves a conditional in nextopt's param.
12885 */
12886 flag_off = 0;
12887 while ((opt = nextopt("np")) != '\0') {
12888 if (opt == 'n')
12889 flag_off = VEXPORT;
12890 }
12891 flag = VEXPORT;
12892 if (argv[0][0] == 'r') {
12893 flag = VREADONLY;
12894 flag_off = 0; /* readonly ignores -n */
12895 }
12896 flag_off = ~flag_off;
12897
12898 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12899 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012900 aptr = argptr;
12901 name = *aptr;
12902 if (name) {
12903 do {
12904 p = strchr(name, '=');
12905 if (p != NULL) {
12906 p++;
12907 } else {
12908 vp = *findvar(hashvar(name), name);
12909 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012910 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012911 continue;
12912 }
Eric Andersencb57d552001-06-28 07:25:16 +000012913 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012914 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012915 } while ((name = *++aptr) != NULL);
12916 return 0;
12917 }
Eric Andersencb57d552001-06-28 07:25:16 +000012918 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012919
12920 /* No arguments. Show the list of exported or readonly vars.
12921 * -n is ignored.
12922 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012923 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012924 return 0;
12925}
12926
Eric Andersencb57d552001-06-28 07:25:16 +000012927/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012928 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012929 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012930static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012931unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012932{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012933 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012934
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012935 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012936 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012937 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012938}
12939
Eric Andersencb57d552001-06-28 07:25:16 +000012940/*
Eric Andersencb57d552001-06-28 07:25:16 +000012941 * The unset builtin command. We unset the function before we unset the
12942 * variable to allow a function to be unset when there is a readonly variable
12943 * with the same name.
12944 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012945static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012946unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012947{
12948 char **ap;
12949 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012950 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012951 int ret = 0;
12952
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012953 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012954 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012955 }
Eric Andersencb57d552001-06-28 07:25:16 +000012956
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012957 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012958 if (flag != 'f') {
12959 i = unsetvar(*ap);
12960 ret |= i;
12961 if (!(i & 2))
12962 continue;
12963 }
12964 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012965 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012966 }
Eric Andersenc470f442003-07-28 09:56:35 +000012967 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012968}
12969
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012970static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012971 ' ', offsetof(struct tms, tms_utime),
12972 '\n', offsetof(struct tms, tms_stime),
12973 ' ', offsetof(struct tms, tms_cutime),
12974 '\n', offsetof(struct tms, tms_cstime),
12975 0
12976};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012977static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012978timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012979{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012980 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012981 const unsigned char *p;
12982 struct tms buf;
12983
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012984 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012985 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012986
12987 p = timescmd_str;
12988 do {
12989 t = *(clock_t *)(((char *) &buf) + p[1]);
12990 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012991 t = t % clk_tck;
12992 out1fmt("%lum%lu.%03lus%c",
12993 s / 60, s % 60,
12994 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012995 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012996 p += 2;
12997 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012998
Eric Andersencb57d552001-06-28 07:25:16 +000012999 return 0;
13000}
13001
Mike Frysinger98c52642009-04-02 10:02:37 +000013002#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000013003/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020013004 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013005 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000013006 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013007 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000013008 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013009static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013010letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013011{
Denis Vlasenko68404f12008-03-17 09:00:54 +000013012 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000013013
Denis Vlasenko68404f12008-03-17 09:00:54 +000013014 argv++;
13015 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000013016 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000013017 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000013018 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013019 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013020
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000013021 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000013022}
Eric Andersenc470f442003-07-28 09:56:35 +000013023#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000013024
Eric Andersenc470f442003-07-28 09:56:35 +000013025/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013026 * The read builtin. Options:
13027 * -r Do not interpret '\' specially
13028 * -s Turn off echo (tty only)
13029 * -n NCHARS Read NCHARS max
13030 * -p PROMPT Display PROMPT on stderr (if input is from tty)
13031 * -t SECONDS Timeout after SECONDS (tty or pipe only)
13032 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000013033 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013034 * TODO: bash also has:
13035 * -a ARRAY Read into array[0],[1],etc
13036 * -d DELIM End on DELIM char, not newline
13037 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013038 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013039static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013040readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013041{
Denys Vlasenko73067272010-01-12 22:11:24 +010013042 char *opt_n = NULL;
13043 char *opt_p = NULL;
13044 char *opt_t = NULL;
13045 char *opt_u = NULL;
13046 int read_flags = 0;
13047 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013048 int i;
13049
Denys Vlasenko73067272010-01-12 22:11:24 +010013050 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013051 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013052 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013053 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013054 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013055 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013056 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013057 break;
13058 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013059 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013060 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013061 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013062 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013063 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013064 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013065 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013066 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013067 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013068 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013069 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013070 default:
13071 break;
13072 }
Eric Andersenc470f442003-07-28 09:56:35 +000013073 }
Paul Fox02eb9342005-09-07 16:56:02 +000013074
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013075 /* "read -s" needs to save/restore termios, can't allow ^C
13076 * to jump out of it.
13077 */
13078 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013079 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013080 argptr,
13081 bltinlookup("IFS"), /* can be NULL */
13082 read_flags,
13083 opt_n,
13084 opt_p,
13085 opt_t,
13086 opt_u
13087 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013088 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013089
Denys Vlasenko73067272010-01-12 22:11:24 +010013090 if ((uintptr_t)r > 1)
13091 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013092
Denys Vlasenko73067272010-01-12 22:11:24 +010013093 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013094}
13095
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013096static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013097umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013098{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013099 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013100
Eric Andersenc470f442003-07-28 09:56:35 +000013101 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013102 int symbolic_mode = 0;
13103
13104 while (nextopt("S") != '\0') {
13105 symbolic_mode = 1;
13106 }
13107
Denis Vlasenkob012b102007-02-19 22:43:01 +000013108 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013109 mask = umask(0);
13110 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013111 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013112
Denys Vlasenko6283f982015-10-07 16:56:20 +020013113 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013114 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013115 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013116 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013117 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013118
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013119 i = 2;
13120 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013121 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013122 *p++ = permuser[i];
13123 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013124 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013125 if (!(mask & 0400)) *p++ = 'r';
13126 if (!(mask & 0200)) *p++ = 'w';
13127 if (!(mask & 0100)) *p++ = 'x';
13128 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013129 if (--i < 0)
13130 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013131 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013132 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013133 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013134 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013135 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013136 }
13137 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013138 char *modestr = *argptr;
13139 /* numeric umasks are taken as-is */
13140 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13141 if (!isdigit(modestr[0]))
13142 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013143 mask = bb_parse_mode(modestr, mask);
13144 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013145 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013146 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013147 if (!isdigit(modestr[0]))
13148 mask ^= 0777;
13149 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013150 }
13151 return 0;
13152}
13153
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013154static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013155ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013156{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013157 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013158}
13159
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013160/* ============ main() and helpers */
13161
13162/*
13163 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013164 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013165static void
13166exitshell(void)
13167{
13168 struct jmploc loc;
13169 char *p;
13170 int status;
13171
Denys Vlasenkobede2152011-09-04 16:12:33 +020013172#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13173 save_history(line_input_state);
13174#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013175 status = exitstatus;
13176 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13177 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013178 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013179 status = exitstatus;
13180 goto out;
13181 }
13182 exception_handler = &loc;
13183 p = trap[0];
13184 if (p) {
13185 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013186 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013187 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013188 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013189 }
13190 flush_stdout_stderr();
13191 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013192 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13193 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13194 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013195 setjobctl(0);
13196 _exit(status);
13197 /* NOTREACHED */
13198}
13199
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013200static void
13201init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013202{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013203 /* we will never free this */
13204 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013205
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013206 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013207 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13208 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13209 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013210 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013211
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013212 {
13213 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013214 const char *p;
13215 struct stat st1, st2;
13216
13217 initvar();
13218 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013219 p = endofname(*envp);
13220 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013221 setvareq(*envp, VEXPORT|VTEXTFIXED);
13222 }
13223 }
13224
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013225 setvareq((char*)defoptindvar, VTEXTFIXED);
13226
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013227 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013228#if ENABLE_ASH_BASH_COMPAT
13229 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013230 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013231 if (!lookupvar("HOSTNAME")) {
13232 struct utsname uts;
13233 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013234 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013235 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013236#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013237 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013238 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013239 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013240 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13241 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013242 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013243 }
13244 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013245 setpwd(p, 0);
13246 }
13247}
13248
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013249
13250//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013251//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013252//usage:#define ash_full_usage "\n\n"
13253//usage: "Unix shell interpreter"
13254
13255//usage:#if ENABLE_FEATURE_SH_IS_ASH
13256//usage:# define sh_trivial_usage ash_trivial_usage
13257//usage:# define sh_full_usage ash_full_usage
13258//usage:#endif
13259//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13260//usage:# define bash_trivial_usage ash_trivial_usage
13261//usage:# define bash_full_usage ash_full_usage
13262//usage:#endif
13263
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013264/*
13265 * Process the shell command line arguments.
13266 */
13267static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013268procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013269{
13270 int i;
13271 const char *xminusc;
13272 char **xargv;
13273
13274 xargv = argv;
13275 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013276 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013277 xargv++;
13278 for (i = 0; i < NOPTS; i++)
13279 optlist[i] = 2;
13280 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013281 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013282 /* it already printed err message */
13283 raise_exception(EXERROR);
13284 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013285 xargv = argptr;
13286 xminusc = minusc;
13287 if (*xargv == NULL) {
13288 if (xminusc)
13289 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13290 sflag = 1;
13291 }
13292 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13293 iflag = 1;
13294 if (mflag == 2)
13295 mflag = iflag;
13296 for (i = 0; i < NOPTS; i++)
13297 if (optlist[i] == 2)
13298 optlist[i] = 0;
13299#if DEBUG == 2
13300 debug = 1;
13301#endif
13302 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13303 if (xminusc) {
13304 minusc = *xargv++;
13305 if (*xargv)
13306 goto setarg0;
13307 } else if (!sflag) {
13308 setinputfile(*xargv, 0);
13309 setarg0:
13310 arg0 = *xargv++;
13311 commandname = arg0;
13312 }
13313
13314 shellparam.p = xargv;
13315#if ENABLE_ASH_GETOPTS
13316 shellparam.optind = 1;
13317 shellparam.optoff = -1;
13318#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013319 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013320 while (*xargv) {
13321 shellparam.nparam++;
13322 xargv++;
13323 }
13324 optschanged();
13325}
13326
13327/*
13328 * Read /etc/profile or .profile.
13329 */
13330static void
13331read_profile(const char *name)
13332{
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013333 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13334 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013335 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013336 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013337}
13338
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013339/*
13340 * This routine is called when an error or an interrupt occurs in an
13341 * interactive shell and control is returned to the main command loop.
13342 */
13343static void
13344reset(void)
13345{
13346 /* from eval.c: */
13347 evalskip = 0;
13348 loopnest = 0;
13349 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013350 g_parsefile->left_in_buffer = 0;
13351 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013352 popallfiles();
13353 /* from parser.c: */
13354 tokpushback = 0;
13355 checkkwd = 0;
13356 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013357 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013358}
13359
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013360#if PROFILE
13361static short profile_buf[16384];
13362extern int etext();
13363#endif
13364
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013365/*
13366 * Main routine. We initialize things, parse the arguments, execute
13367 * profiles if we're a login shell, and then call cmdloop to execute
13368 * commands. The setjmp call sets up the location to jump to when an
13369 * exception occurs. When an exception occurs the variable "state"
13370 * is used to figure out how far we had gotten.
13371 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013372int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013373int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013374{
Mike Frysinger98c52642009-04-02 10:02:37 +000013375 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013376 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013377 struct jmploc jmploc;
13378 struct stackmark smark;
13379
Denis Vlasenko01631112007-12-16 17:20:38 +000013380 /* Initialize global data */
13381 INIT_G_misc();
13382 INIT_G_memstack();
13383 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013384#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013385 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013386#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013387 INIT_G_cmdtable();
13388
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013389#if PROFILE
13390 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13391#endif
13392
13393#if ENABLE_FEATURE_EDITING
13394 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13395#endif
13396 state = 0;
13397 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013398 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013399 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013400
13401 reset();
13402
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013403 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013404 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013405 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013406 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013407 }
13408 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013409 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013410 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013411
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013412 popstackmark(&smark);
13413 FORCE_INT_ON; /* enable interrupts */
13414 if (s == 1)
13415 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013416 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013417 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013418 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013419 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013420 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013421 }
13422 exception_handler = &jmploc;
13423#if DEBUG
13424 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013425 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013426 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013427#endif
13428 rootpid = getpid();
13429
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013430 init();
13431 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013432 procargs(argv);
13433
Denys Vlasenko6088e132010-12-25 23:58:42 +010013434 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013435 isloginsh = 1;
13436 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013437 const char *hp;
13438
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013439 state = 1;
13440 read_profile("/etc/profile");
13441 state1:
13442 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013443 hp = lookupvar("HOME");
13444 if (hp) {
13445 hp = concat_path_file(hp, ".profile");
13446 read_profile(hp);
13447 free((char*)hp);
13448 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013449 }
13450 state2:
13451 state = 3;
13452 if (
13453#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013454 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013455#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013456 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013457 ) {
13458 shinit = lookupvar("ENV");
13459 if (shinit != NULL && *shinit != '\0') {
13460 read_profile(shinit);
13461 }
13462 }
13463 state3:
13464 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013465 if (minusc) {
13466 /* evalstring pushes parsefile stack.
13467 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013468 * is one of stacked source fds.
13469 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013470 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013471 // ^^ not necessary since now we special-case fd 0
13472 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013473 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013474 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013475
13476 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013477#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013478 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013479 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013480 if (!hp) {
13481 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013482 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013483 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013484 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013485 free((char*)hp);
13486 hp = lookupvar("HISTFILE");
13487 }
13488 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013489 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013490 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013491# if ENABLE_FEATURE_SH_HISTFILESIZE
13492 hp = lookupvar("HISTFILESIZE");
13493 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13494# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013495 }
13496#endif
13497 state4: /* XXX ??? - why isn't this before the "if" statement */
13498 cmdloop(1);
13499 }
13500#if PROFILE
13501 monitor(0);
13502#endif
13503#ifdef GPROF
13504 {
13505 extern void _mcleanup(void);
13506 _mcleanup();
13507 }
13508#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013509 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013510 exitshell();
13511 /* NOTREACHED */
13512}
13513
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013514
Eric Andersendf82f612001-06-28 07:46:40 +000013515/*-
13516 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013517 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013518 *
13519 * This code is derived from software contributed to Berkeley by
13520 * Kenneth Almquist.
13521 *
13522 * Redistribution and use in source and binary forms, with or without
13523 * modification, are permitted provided that the following conditions
13524 * are met:
13525 * 1. Redistributions of source code must retain the above copyright
13526 * notice, this list of conditions and the following disclaimer.
13527 * 2. Redistributions in binary form must reproduce the above copyright
13528 * notice, this list of conditions and the following disclaimer in the
13529 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013530 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013531 * may be used to endorse or promote products derived from this software
13532 * without specific prior written permission.
13533 *
13534 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13535 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13536 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13537 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13538 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13539 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13540 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13541 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13542 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13543 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13544 * SUCH DAMAGE.
13545 */