blob: 3a364dc2c021b6d5e382b21a3fce8b394ad61d86 [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;
Denis Vlasenko01631112007-12-16 17:20:38 +00001402 struct stack_block stackbase;
1403};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001404extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1405#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001406#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001407#define g_stacknxt (G_memstack.g_stacknxt )
1408#define sstrend (G_memstack.sstrend )
1409#define g_stacknleft (G_memstack.g_stacknleft)
Denis Vlasenko01631112007-12-16 17:20:38 +00001410#define stackbase (G_memstack.stackbase )
1411#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001412 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1413 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001414 g_stackp = &stackbase; \
1415 g_stacknxt = stackbase.space; \
1416 g_stacknleft = MINSIZE; \
1417 sstrend = stackbase.space + MINSIZE; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001418} while (0)
1419
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001420
Denis Vlasenko01631112007-12-16 17:20:38 +00001421#define stackblock() ((void *)g_stacknxt)
1422#define stackblocksize() g_stacknleft
1423
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001424/*
1425 * Parse trees for commands are allocated in lifo order, so we use a stack
1426 * to make this more efficient, and also to avoid all sorts of exception
1427 * handling code to handle interrupts in the middle of a parse.
1428 *
1429 * The size 504 was chosen because the Ultrix malloc handles that size
1430 * well.
1431 */
1432static void *
1433stalloc(size_t nbytes)
1434{
1435 char *p;
1436 size_t aligned;
1437
1438 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001439 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001440 size_t len;
1441 size_t blocksize;
1442 struct stack_block *sp;
1443
1444 blocksize = aligned;
1445 if (blocksize < MINSIZE)
1446 blocksize = MINSIZE;
1447 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1448 if (len < blocksize)
1449 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1450 INT_OFF;
1451 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001452 sp->prev = g_stackp;
1453 g_stacknxt = sp->space;
1454 g_stacknleft = blocksize;
1455 sstrend = g_stacknxt + blocksize;
1456 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001457 INT_ON;
1458 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001459 p = g_stacknxt;
1460 g_stacknxt += aligned;
1461 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001462 return p;
1463}
1464
Denis Vlasenko597906c2008-02-20 16:38:54 +00001465static void *
1466stzalloc(size_t nbytes)
1467{
1468 return memset(stalloc(nbytes), 0, nbytes);
1469}
1470
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001471static void
1472stunalloc(void *p)
1473{
1474#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001475 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001476 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001477 abort();
1478 }
1479#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001480 g_stacknleft += g_stacknxt - (char *)p;
1481 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001482}
1483
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001484/*
1485 * Like strdup but works with the ash stack.
1486 */
1487static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001488sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001489{
1490 size_t len = strlen(p) + 1;
1491 return memcpy(stalloc(len), p, len);
1492}
1493
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001494static inline void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001495grabstackblock(size_t len)
1496{
Denys Vlasenkoa318bba2016-10-26 18:26:27 +02001497 stalloc(len);
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001498}
1499
1500static void
1501pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001502{
Denis Vlasenko01631112007-12-16 17:20:38 +00001503 mark->stackp = g_stackp;
1504 mark->stacknxt = g_stacknxt;
1505 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001506 grabstackblock(len);
1507}
1508
1509static void
1510setstackmark(struct stackmark *mark)
1511{
1512 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001513}
1514
1515static void
1516popstackmark(struct stackmark *mark)
1517{
1518 struct stack_block *sp;
1519
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001520 if (!mark->stackp)
1521 return;
1522
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001523 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001524 while (g_stackp != mark->stackp) {
1525 sp = g_stackp;
1526 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001527 free(sp);
1528 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001529 g_stacknxt = mark->stacknxt;
1530 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001531 sstrend = mark->stacknxt + mark->stacknleft;
1532 INT_ON;
1533}
1534
1535/*
1536 * When the parser reads in a string, it wants to stick the string on the
1537 * stack and only adjust the stack pointer when it knows how big the
1538 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1539 * of space on top of the stack and stackblocklen returns the length of
1540 * this block. Growstackblock will grow this space by at least one byte,
1541 * possibly moving it (like realloc). Grabstackblock actually allocates the
1542 * part of the block that has been used.
1543 */
1544static void
1545growstackblock(void)
1546{
1547 size_t newlen;
1548
Denis Vlasenko01631112007-12-16 17:20:38 +00001549 newlen = g_stacknleft * 2;
1550 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001551 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1552 if (newlen < 128)
1553 newlen += 128;
1554
Denis Vlasenko01631112007-12-16 17:20:38 +00001555 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001556 struct stack_block *sp;
1557 struct stack_block *prevstackp;
1558 size_t grosslen;
1559
1560 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001561 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001562 prevstackp = sp->prev;
1563 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1564 sp = ckrealloc(sp, grosslen);
1565 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001566 g_stackp = sp;
1567 g_stacknxt = sp->space;
1568 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001569 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001570 INT_ON;
1571 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001572 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001573 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001574 char *p = stalloc(newlen);
1575
1576 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001577 g_stacknxt = memcpy(p, oldspace, oldlen);
1578 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001579 }
1580}
1581
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001582/*
1583 * The following routines are somewhat easier to use than the above.
1584 * The user declares a variable of type STACKSTR, which may be declared
1585 * to be a register. The macro STARTSTACKSTR initializes things. Then
1586 * the user uses the macro STPUTC to add characters to the string. In
1587 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1588 * grown as necessary. When the user is done, she can just leave the
1589 * string there and refer to it using stackblock(). Or she can allocate
1590 * the space for it using grabstackstr(). If it is necessary to allow
1591 * someone else to use the stack temporarily and then continue to grow
1592 * the string, the user should use grabstack to allocate the space, and
1593 * then call ungrabstr(p) to return to the previous mode of operation.
1594 *
1595 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1596 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1597 * is space for at least one character.
1598 */
1599static void *
1600growstackstr(void)
1601{
1602 size_t len = stackblocksize();
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001603 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001604 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001605}
1606
1607/*
1608 * Called from CHECKSTRSPACE.
1609 */
1610static char *
1611makestrspace(size_t newlen, char *p)
1612{
Denis Vlasenko01631112007-12-16 17:20:38 +00001613 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001614 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001615
1616 for (;;) {
1617 size_t nleft;
1618
1619 size = stackblocksize();
1620 nleft = size - len;
1621 if (nleft >= newlen)
1622 break;
1623 growstackblock();
1624 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001625 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001626}
1627
1628static char *
1629stack_nputstr(const char *s, size_t n, char *p)
1630{
1631 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001632 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001633 return p;
1634}
1635
1636static char *
1637stack_putstr(const char *s, char *p)
1638{
1639 return stack_nputstr(s, strlen(s), p);
1640}
1641
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001642static char *
1643_STPUTC(int c, char *p)
1644{
1645 if (p == sstrend)
1646 p = growstackstr();
1647 *p++ = c;
1648 return p;
1649}
1650
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001651#define STARTSTACKSTR(p) ((p) = stackblock())
1652#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001653#define CHECKSTRSPACE(n, p) do { \
1654 char *q = (p); \
1655 size_t l = (n); \
1656 size_t m = sstrend - q; \
1657 if (l > m) \
1658 (p) = makestrspace(l, q); \
1659} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001660#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001661#define STACKSTRNUL(p) do { \
1662 if ((p) == sstrend) \
1663 (p) = growstackstr(); \
1664 *(p) = '\0'; \
1665} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001666#define STUNPUTC(p) (--(p))
1667#define STTOPC(p) ((p)[-1])
1668#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001669
1670#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001671#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001672#define stackstrend() ((void *)sstrend)
1673
1674
1675/* ============ String helpers */
1676
1677/*
1678 * prefix -- see if pfx is a prefix of string.
1679 */
1680static char *
1681prefix(const char *string, const char *pfx)
1682{
1683 while (*pfx) {
1684 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001685 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001686 }
1687 return (char *) string;
1688}
1689
1690/*
1691 * Check for a valid number. This should be elsewhere.
1692 */
1693static int
1694is_number(const char *p)
1695{
1696 do {
1697 if (!isdigit(*p))
1698 return 0;
1699 } while (*++p != '\0');
1700 return 1;
1701}
1702
1703/*
1704 * Convert a string of digits to an integer, printing an error message on
1705 * failure.
1706 */
1707static int
1708number(const char *s)
1709{
1710 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001711 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001712 return atoi(s);
1713}
1714
1715/*
1716 * Produce a possibly single quoted string suitable as input to the shell.
1717 * The return string is allocated on the stack.
1718 */
1719static char *
1720single_quote(const char *s)
1721{
1722 char *p;
1723
1724 STARTSTACKSTR(p);
1725
1726 do {
1727 char *q;
1728 size_t len;
1729
1730 len = strchrnul(s, '\'') - s;
1731
1732 q = p = makestrspace(len + 3, p);
1733
1734 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001735 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001736 *q++ = '\'';
1737 s += len;
1738
1739 STADJUST(q - p, p);
1740
Denys Vlasenkocd716832009-11-28 22:14:02 +01001741 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001742 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001743 len = 0;
1744 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001745
1746 q = p = makestrspace(len + 3, p);
1747
1748 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001749 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001750 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001751
1752 STADJUST(q - p, p);
1753 } while (*s);
1754
Denys Vlasenkocd716832009-11-28 22:14:02 +01001755 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001756
1757 return stackblock();
1758}
1759
1760
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001761/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001762
1763static char **argptr; /* argument list for builtin commands */
1764static char *optionarg; /* set by nextopt (like getopt) */
1765static char *optptr; /* used by nextopt */
1766
1767/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001768 * XXX - should get rid of. Have all builtins use getopt(3).
1769 * The library getopt must have the BSD extension static variable
1770 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001771 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001772 * Standard option processing (a la getopt) for builtin routines.
1773 * The only argument that is passed to nextopt is the option string;
1774 * the other arguments are unnecessary. It returns the character,
1775 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001776 */
1777static int
1778nextopt(const char *optstring)
1779{
1780 char *p;
1781 const char *q;
1782 char c;
1783
1784 p = optptr;
1785 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001786 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001787 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001788 if (p == NULL)
1789 return '\0';
1790 if (*p != '-')
1791 return '\0';
1792 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001793 return '\0';
1794 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001795 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001796 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001797 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001798 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001799 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001800 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001801 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001802 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001803 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001804 if (*++q == ':')
1805 q++;
1806 }
1807 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001808 if (*p == '\0') {
1809 p = *argptr++;
1810 if (p == NULL)
1811 ash_msg_and_raise_error("no arg for -%c option", c);
1812 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001813 optionarg = p;
1814 p = NULL;
1815 }
1816 optptr = p;
1817 return c;
1818}
1819
1820
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001821/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001822
Denis Vlasenko01631112007-12-16 17:20:38 +00001823/*
1824 * The parsefile structure pointed to by the global variable parsefile
1825 * contains information about the current file being read.
1826 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001827struct shparam {
1828 int nparam; /* # of positional parameters (without $0) */
1829#if ENABLE_ASH_GETOPTS
1830 int optind; /* next parameter to be processed by getopts */
1831 int optoff; /* used by getopts */
1832#endif
1833 unsigned char malloced; /* if parameter list dynamically allocated */
1834 char **p; /* parameter list */
1835};
1836
1837/*
1838 * Free the list of positional parameters.
1839 */
1840static void
1841freeparam(volatile struct shparam *param)
1842{
Denis Vlasenko01631112007-12-16 17:20:38 +00001843 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001844 char **ap, **ap1;
1845 ap = ap1 = param->p;
1846 while (*ap)
1847 free(*ap++);
1848 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001849 }
1850}
1851
1852#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001853static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001854#endif
1855
1856struct var {
1857 struct var *next; /* next entry in hash list */
1858 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001859 const char *var_text; /* name=value */
1860 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001861 /* the variable gets set/unset */
1862};
1863
1864struct localvar {
1865 struct localvar *next; /* next local variable in list */
1866 struct var *vp; /* the variable that was made local */
1867 int flags; /* saved flags */
1868 const char *text; /* saved text */
1869};
1870
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001871/* flags */
1872#define VEXPORT 0x01 /* variable is exported */
1873#define VREADONLY 0x02 /* variable cannot be modified */
1874#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1875#define VTEXTFIXED 0x08 /* text is statically allocated */
1876#define VSTACK 0x10 /* text is allocated on the stack */
1877#define VUNSET 0x20 /* the variable is not set */
1878#define VNOFUNC 0x40 /* don't call the callback function */
1879#define VNOSET 0x80 /* do not set variable - just readonly test */
1880#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001881#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001882# define VDYNAMIC 0x200 /* dynamic variable */
1883#else
1884# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001885#endif
1886
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001887
Denis Vlasenko01631112007-12-16 17:20:38 +00001888/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001889#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001890static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001891change_lc_all(const char *value)
1892{
1893 if (value && *value != '\0')
1894 setlocale(LC_ALL, value);
1895}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001896static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001897change_lc_ctype(const char *value)
1898{
1899 if (value && *value != '\0')
1900 setlocale(LC_CTYPE, value);
1901}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001902#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001903#if ENABLE_ASH_MAIL
1904static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001905static void changemail(const char *var_value) FAST_FUNC;
1906#else
1907# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001908#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001909static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001910#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001911static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001912#endif
1913
Denis Vlasenko01631112007-12-16 17:20:38 +00001914static const struct {
1915 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001916 const char *var_text;
1917 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001918} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001919 /*
1920 * Note: VEXPORT would not work correctly here for NOFORK applets:
1921 * some environment strings may be constant.
1922 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001923 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001924#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001925 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1926 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001927#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001928 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1929 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1930 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1931 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001932#if ENABLE_ASH_GETOPTS
Denys Vlasenkoe627ac92016-09-30 14:36:59 +02001933 { VSTRFIXED|VTEXTFIXED , defoptindvar, getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001934#endif
1935#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001936 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001937#endif
1938#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001939 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1940 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001941#endif
1942#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001943 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001944#endif
1945};
1946
Denis Vlasenko0b769642008-07-24 07:54:57 +00001947struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001948
1949struct globals_var {
1950 struct shparam shellparam; /* $@ current positional parameters */
1951 struct redirtab *redirlist;
Denis Vlasenko01631112007-12-16 17:20:38 +00001952 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1953 struct var *vartab[VTABSIZE];
1954 struct var varinit[ARRAY_SIZE(varinit_data)];
1955};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001956extern struct globals_var *const ash_ptr_to_globals_var;
1957#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001958#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001959//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001960#define preverrout_fd (G_var.preverrout_fd)
1961#define vartab (G_var.vartab )
1962#define varinit (G_var.varinit )
1963#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001964 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001965 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1966 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001967 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001968 varinit[i].flags = varinit_data[i].flags; \
1969 varinit[i].var_text = varinit_data[i].var_text; \
1970 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001971 } \
1972} while (0)
1973
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001974#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001975#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001976# define vmail (&vifs)[1]
1977# define vmpath (&vmail)[1]
1978# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001979#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001980# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001981#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001982#define vps1 (&vpath)[1]
1983#define vps2 (&vps1)[1]
1984#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001985#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001986# define voptind (&vps4)[1]
1987# if ENABLE_ASH_RANDOM_SUPPORT
1988# define vrandom (&voptind)[1]
1989# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001990#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001991# if ENABLE_ASH_RANDOM_SUPPORT
1992# define vrandom (&vps4)[1]
1993# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001994#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001995
1996/*
1997 * The following macros access the values of the above variables.
1998 * They have to skip over the name. They return the null string
1999 * for unset variables.
2000 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002001#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002002#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002003#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002004# define mailval() (vmail.var_text + 5)
2005# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002006# define mpathset() ((vmpath.flags & VUNSET) == 0)
2007#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002008#define pathval() (vpath.var_text + 5)
2009#define ps1val() (vps1.var_text + 4)
2010#define ps2val() (vps2.var_text + 4)
2011#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002012#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002013# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002014#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002015
Denis Vlasenko01631112007-12-16 17:20:38 +00002016#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002017static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002018getoptsreset(const char *value)
2019{
Denys Vlasenkoa513bf32016-10-26 02:03:37 +02002020 shellparam.optind = number(value) ?: 1;
Denis Vlasenko01631112007-12-16 17:20:38 +00002021 shellparam.optoff = -1;
2022}
2023#endif
2024
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002025/*
2026 * Compares two strings up to the first = or '\0'. The first
2027 * string must be terminated by '='; the second may be terminated by
2028 * either '=' or '\0'.
2029 */
2030static int
2031varcmp(const char *p, const char *q)
2032{
2033 int c, d;
2034
2035 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002036 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002037 goto out;
2038 p++;
2039 q++;
2040 }
2041 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002042 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002043 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002044 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002045 out:
2046 return c - d;
2047}
2048
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002049/*
2050 * Find the appropriate entry in the hash table from the name.
2051 */
2052static struct var **
2053hashvar(const char *p)
2054{
2055 unsigned hashval;
2056
2057 hashval = ((unsigned char) *p) << 4;
2058 while (*p && *p != '=')
2059 hashval += (unsigned char) *p++;
2060 return &vartab[hashval % VTABSIZE];
2061}
2062
2063static int
2064vpcmp(const void *a, const void *b)
2065{
2066 return varcmp(*(const char **)a, *(const char **)b);
2067}
2068
2069/*
2070 * This routine initializes the builtin variables.
2071 */
2072static void
2073initvar(void)
2074{
2075 struct var *vp;
2076 struct var *end;
2077 struct var **vpp;
2078
2079 /*
2080 * PS1 depends on uid
2081 */
2082#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002083 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002084#else
2085 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002086 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002087#endif
2088 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002089 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002090 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002091 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002092 vp->next = *vpp;
2093 *vpp = vp;
2094 } while (++vp < end);
2095}
2096
2097static struct var **
2098findvar(struct var **vpp, const char *name)
2099{
2100 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002101 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002102 break;
2103 }
2104 }
2105 return vpp;
2106}
2107
2108/*
2109 * Find the value of a variable. Returns NULL if not set.
2110 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002111static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002112lookupvar(const char *name)
2113{
2114 struct var *v;
2115
2116 v = *findvar(hashvar(name), name);
2117 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002118#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002119 /*
2120 * Dynamic variables are implemented roughly the same way they are
2121 * in bash. Namely, they're "special" so long as they aren't unset.
2122 * As soon as they're unset, they're no longer dynamic, and dynamic
2123 * lookup will no longer happen at that point. -- PFM.
2124 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002125 if (v->flags & VDYNAMIC)
2126 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002127#endif
2128 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002129 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002130 }
2131 return NULL;
2132}
2133
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02002134static void
2135reinit_unicode_for_ash(void)
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002136{
2137 /* Unicode support should be activated even if LANG is set
2138 * _during_ shell execution, not only if it was set when
2139 * shell was started. Therefore, re-check LANG every time:
2140 */
2141 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2142 || ENABLE_UNICODE_USING_LOCALE
2143 ) {
2144 const char *s = lookupvar("LC_ALL");
2145 if (!s) s = lookupvar("LC_CTYPE");
2146 if (!s) s = lookupvar("LANG");
2147 reinit_unicode(s);
2148 }
2149}
2150
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002151/*
2152 * Search the environment of a builtin command.
2153 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002154static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002155bltinlookup(const char *name)
2156{
2157 struct strlist *sp;
2158
2159 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002160 if (varcmp(sp->text, name) == 0)
2161 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002162 }
2163 return lookupvar(name);
2164}
2165
2166/*
2167 * Same as setvar except that the variable and value are passed in
2168 * the first argument as name=value. Since the first argument will
2169 * be actually stored in the table, it should not be a string that
2170 * will go away.
2171 * Called with interrupts off.
2172 */
2173static void
2174setvareq(char *s, int flags)
2175{
2176 struct var *vp, **vpp;
2177
2178 vpp = hashvar(s);
2179 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2180 vp = *findvar(vpp, s);
2181 if (vp) {
2182 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2183 const char *n;
2184
2185 if (flags & VNOSAVE)
2186 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002187 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002188 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2189 }
2190
2191 if (flags & VNOSET)
2192 return;
2193
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002194 if (vp->var_func && !(flags & VNOFUNC))
2195 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002196
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002197 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2198 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002199
2200 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2201 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002202 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002203 if (flags & VNOSET)
2204 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002205 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002206 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002207 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002208 *vpp = vp;
2209 }
2210 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2211 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002212 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002213 vp->flags = flags;
2214}
2215
2216/*
2217 * Set the value of a variable. The flags argument is ored with the
2218 * flags of the variable. If val is NULL, the variable is unset.
2219 */
2220static void
2221setvar(const char *name, const char *val, int flags)
2222{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002223 const char *q;
2224 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002225 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002226 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002227 size_t vallen;
2228
2229 q = endofname(name);
2230 p = strchrnul(q, '=');
2231 namelen = p - name;
2232 if (!namelen || p != q)
2233 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2234 vallen = 0;
2235 if (val == NULL) {
2236 flags |= VUNSET;
2237 } else {
2238 vallen = strlen(val);
2239 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002240
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002241 INT_OFF;
2242 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002243 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002244 if (val) {
2245 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002246 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002247 }
2248 *p = '\0';
2249 setvareq(nameeq, flags | VNOSAVE);
2250 INT_ON;
2251}
2252
Denys Vlasenko03dad222010-01-12 23:29:57 +01002253static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002254setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002255{
2256 setvar(name, val, 0);
2257}
2258
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002259/*
2260 * Unset the specified variable.
2261 */
2262static int
2263unsetvar(const char *s)
2264{
2265 struct var **vpp;
2266 struct var *vp;
2267 int retval;
2268
2269 vpp = findvar(hashvar(s), s);
2270 vp = *vpp;
2271 retval = 2;
2272 if (vp) {
2273 int flags = vp->flags;
2274
2275 retval = 1;
2276 if (flags & VREADONLY)
2277 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002278#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002279 vp->flags &= ~VDYNAMIC;
2280#endif
2281 if (flags & VUNSET)
2282 goto ok;
2283 if ((flags & VSTRFIXED) == 0) {
2284 INT_OFF;
2285 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002286 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002287 *vpp = vp->next;
2288 free(vp);
2289 INT_ON;
2290 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002291 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002292 vp->flags &= ~VEXPORT;
2293 }
2294 ok:
2295 retval = 0;
2296 }
2297 out:
2298 return retval;
2299}
2300
2301/*
2302 * Process a linked list of variable assignments.
2303 */
2304static void
2305listsetvar(struct strlist *list_set_var, int flags)
2306{
2307 struct strlist *lp = list_set_var;
2308
2309 if (!lp)
2310 return;
2311 INT_OFF;
2312 do {
2313 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002314 lp = lp->next;
2315 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002316 INT_ON;
2317}
2318
2319/*
2320 * Generate a list of variables satisfying the given conditions.
2321 */
2322static char **
2323listvars(int on, int off, char ***end)
2324{
2325 struct var **vpp;
2326 struct var *vp;
2327 char **ep;
2328 int mask;
2329
2330 STARTSTACKSTR(ep);
2331 vpp = vartab;
2332 mask = on | off;
2333 do {
2334 for (vp = *vpp; vp; vp = vp->next) {
2335 if ((vp->flags & mask) == on) {
2336 if (ep == stackstrend())
2337 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002338 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002339 }
2340 }
2341 } while (++vpp < vartab + VTABSIZE);
2342 if (ep == stackstrend())
2343 ep = growstackstr();
2344 if (end)
2345 *end = ep;
2346 *ep++ = NULL;
2347 return grabstackstr(ep);
2348}
2349
2350
2351/* ============ Path search helper
2352 *
2353 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002354 * of the path before the first call; path_advance will update
2355 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002356 * the possible path expansions in sequence. If an option (indicated by
2357 * a percent sign) appears in the path entry then the global variable
2358 * pathopt will be set to point to it; otherwise pathopt will be set to
2359 * NULL.
2360 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002361static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002362
2363static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002364path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002365{
2366 const char *p;
2367 char *q;
2368 const char *start;
2369 size_t len;
2370
2371 if (*path == NULL)
2372 return NULL;
2373 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002374 for (p = start; *p && *p != ':' && *p != '%'; p++)
2375 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002376 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2377 while (stackblocksize() < len)
2378 growstackblock();
2379 q = stackblock();
2380 if (p != start) {
2381 memcpy(q, start, p - start);
2382 q += p - start;
2383 *q++ = '/';
2384 }
2385 strcpy(q, name);
2386 pathopt = NULL;
2387 if (*p == '%') {
2388 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002389 while (*p && *p != ':')
2390 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002391 }
2392 if (*p == ':')
2393 *path = p + 1;
2394 else
2395 *path = NULL;
2396 return stalloc(len);
2397}
2398
2399
2400/* ============ Prompt */
2401
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002402static smallint doprompt; /* if set, prompt the user */
2403static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002404
2405#if ENABLE_FEATURE_EDITING
2406static line_input_t *line_input_state;
2407static const char *cmdedit_prompt;
2408static void
2409putprompt(const char *s)
2410{
2411 if (ENABLE_ASH_EXPAND_PRMT) {
2412 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002413 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002414 return;
2415 }
2416 cmdedit_prompt = s;
2417}
2418#else
2419static void
2420putprompt(const char *s)
2421{
2422 out2str(s);
2423}
2424#endif
2425
2426#if ENABLE_ASH_EXPAND_PRMT
2427/* expandstr() needs parsing machinery, so it is far away ahead... */
2428static const char *expandstr(const char *ps);
2429#else
2430#define expandstr(s) s
2431#endif
2432
2433static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002434setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002435{
2436 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002437 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2438
2439 if (!do_set)
2440 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002441
2442 needprompt = 0;
2443
2444 switch (whichprompt) {
2445 case 1:
2446 prompt = ps1val();
2447 break;
2448 case 2:
2449 prompt = ps2val();
2450 break;
2451 default: /* 0 */
2452 prompt = nullstr;
2453 }
2454#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002455 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002456#endif
2457 putprompt(expandstr(prompt));
2458#if ENABLE_ASH_EXPAND_PRMT
2459 popstackmark(&smark);
2460#endif
2461}
2462
2463
2464/* ============ The cd and pwd commands */
2465
2466#define CD_PHYSICAL 1
2467#define CD_PRINT 2
2468
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002469static int
2470cdopt(void)
2471{
2472 int flags = 0;
2473 int i, j;
2474
2475 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002476 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002477 if (i != j) {
2478 flags ^= CD_PHYSICAL;
2479 j = i;
2480 }
2481 }
2482
2483 return flags;
2484}
2485
2486/*
2487 * Update curdir (the name of the current directory) in response to a
2488 * cd command.
2489 */
2490static const char *
2491updatepwd(const char *dir)
2492{
2493 char *new;
2494 char *p;
2495 char *cdcomppath;
2496 const char *lim;
2497
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002498 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002499 STARTSTACKSTR(new);
2500 if (*dir != '/') {
2501 if (curdir == nullstr)
2502 return 0;
2503 new = stack_putstr(curdir, new);
2504 }
2505 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002506 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002507 if (*dir != '/') {
2508 if (new[-1] != '/')
2509 USTPUTC('/', new);
2510 if (new > lim && *lim == '/')
2511 lim++;
2512 } else {
2513 USTPUTC('/', new);
2514 cdcomppath++;
2515 if (dir[1] == '/' && dir[2] != '/') {
2516 USTPUTC('/', new);
2517 cdcomppath++;
2518 lim++;
2519 }
2520 }
2521 p = strtok(cdcomppath, "/");
2522 while (p) {
2523 switch (*p) {
2524 case '.':
2525 if (p[1] == '.' && p[2] == '\0') {
2526 while (new > lim) {
2527 STUNPUTC(new);
2528 if (new[-1] == '/')
2529 break;
2530 }
2531 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002532 }
2533 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002534 break;
2535 /* fall through */
2536 default:
2537 new = stack_putstr(p, new);
2538 USTPUTC('/', new);
2539 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002540 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002541 }
2542 if (new > lim)
2543 STUNPUTC(new);
2544 *new = 0;
2545 return stackblock();
2546}
2547
2548/*
2549 * Find out what the current directory is. If we already know the current
2550 * directory, this routine returns immediately.
2551 */
2552static char *
2553getpwd(void)
2554{
Denis Vlasenko01631112007-12-16 17:20:38 +00002555 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002556 return dir ? dir : nullstr;
2557}
2558
2559static void
2560setpwd(const char *val, int setold)
2561{
2562 char *oldcur, *dir;
2563
2564 oldcur = dir = curdir;
2565
2566 if (setold) {
2567 setvar("OLDPWD", oldcur, VEXPORT);
2568 }
2569 INT_OFF;
2570 if (physdir != nullstr) {
2571 if (physdir != oldcur)
2572 free(physdir);
2573 physdir = nullstr;
2574 }
2575 if (oldcur == val || !val) {
2576 char *s = getpwd();
2577 physdir = s;
2578 if (!val)
2579 dir = s;
2580 } else
2581 dir = ckstrdup(val);
2582 if (oldcur != dir && oldcur != nullstr) {
2583 free(oldcur);
2584 }
2585 curdir = dir;
2586 INT_ON;
2587 setvar("PWD", dir, VEXPORT);
2588}
2589
2590static void hashcd(void);
2591
2592/*
Denys Vlasenko70392332016-10-27 02:31:55 +02002593 * Actually do the chdir. We also call hashcd to let other routines
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002594 * know that the current directory has changed.
2595 */
2596static int
2597docd(const char *dest, int flags)
2598{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002599 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002600 int err;
2601
2602 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2603
2604 INT_OFF;
2605 if (!(flags & CD_PHYSICAL)) {
2606 dir = updatepwd(dest);
2607 if (dir)
2608 dest = dir;
2609 }
2610 err = chdir(dest);
2611 if (err)
2612 goto out;
2613 setpwd(dir, 1);
2614 hashcd();
2615 out:
2616 INT_ON;
2617 return err;
2618}
2619
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002620static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002621cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002622{
2623 const char *dest;
2624 const char *path;
2625 const char *p;
2626 char c;
2627 struct stat statb;
2628 int flags;
2629
2630 flags = cdopt();
2631 dest = *argptr;
2632 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002633 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002634 else if (LONE_DASH(dest)) {
2635 dest = bltinlookup("OLDPWD");
2636 flags |= CD_PRINT;
2637 }
2638 if (!dest)
2639 dest = nullstr;
2640 if (*dest == '/')
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002641 goto step6;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002642 if (*dest == '.') {
2643 c = dest[1];
2644 dotdot:
2645 switch (c) {
2646 case '\0':
2647 case '/':
2648 goto step6;
2649 case '.':
2650 c = dest[2];
2651 if (c != '.')
2652 goto dotdot;
2653 }
2654 }
2655 if (!*dest)
2656 dest = ".";
2657 path = bltinlookup("CDPATH");
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002658 while (path) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002659 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002660 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002661 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2662 if (c && c != ':')
2663 flags |= CD_PRINT;
2664 docd:
2665 if (!docd(p, flags))
2666 goto out;
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002667 goto err;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002668 }
Denys Vlasenko0e081d02016-10-26 19:56:05 +02002669 }
2670
2671 step6:
2672 p = dest;
2673 goto docd;
2674
2675 err:
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002676 ash_msg_and_raise_error("can't cd to %s", dest);
2677 /* NOTREACHED */
2678 out:
2679 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002680 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002681 return 0;
2682}
2683
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002684static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002685pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002686{
2687 int flags;
2688 const char *dir = curdir;
2689
2690 flags = cdopt();
2691 if (flags) {
2692 if (physdir == nullstr)
2693 setpwd(dir, 0);
2694 dir = physdir;
2695 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002696 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002697 return 0;
2698}
2699
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002700
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002701/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002702
Denis Vlasenko834dee72008-10-07 09:18:30 +00002703
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002704#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002705
Eric Andersenc470f442003-07-28 09:56:35 +00002706/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002707#define CWORD 0 /* character is nothing special */
2708#define CNL 1 /* newline character */
2709#define CBACK 2 /* a backslash character */
2710#define CSQUOTE 3 /* single quote */
2711#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002712#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002713#define CBQUOTE 6 /* backwards single quote */
2714#define CVAR 7 /* a dollar sign */
2715#define CENDVAR 8 /* a '}' character */
2716#define CLP 9 /* a left paren in arithmetic */
2717#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002718#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002719#define CCTL 12 /* like CWORD, except it must be escaped */
2720#define CSPCL 13 /* these terminate a word */
2721#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002722
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002723#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002724#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002725# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002726#endif
2727
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002728#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002729
Mike Frysinger98c52642009-04-02 10:02:37 +00002730#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002731# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002732#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002733# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002734#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002735static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002736#if ENABLE_ASH_ALIAS
2737 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2738#endif
2739 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2740 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2741 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2742 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2743 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2744 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2745 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2746 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2747 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2748 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2749 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002750#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002751 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2752 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2753 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2754#endif
2755#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002756};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002757/* Constants below must match table above */
2758enum {
2759#if ENABLE_ASH_ALIAS
2760 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2761#endif
2762 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2763 CNL_CNL_CNL_CNL , /* 2 */
2764 CWORD_CCTL_CCTL_CWORD , /* 3 */
2765 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2766 CVAR_CVAR_CWORD_CVAR , /* 5 */
2767 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2768 CSPCL_CWORD_CWORD_CLP , /* 7 */
2769 CSPCL_CWORD_CWORD_CRP , /* 8 */
2770 CBACK_CBACK_CCTL_CBACK , /* 9 */
2771 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2772 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2773 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2774 CWORD_CWORD_CWORD_CWORD , /* 13 */
2775 CCTL_CCTL_CCTL_CCTL , /* 14 */
2776};
Eric Andersen2870d962001-07-02 17:27:21 +00002777
Denys Vlasenkocd716832009-11-28 22:14:02 +01002778/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2779 * caller must ensure proper cast on it if c is *char_ptr!
2780 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002781/* Values for syntax param */
2782#define BASESYNTAX 0 /* not in quotes */
2783#define DQSYNTAX 1 /* in double quotes */
2784#define SQSYNTAX 2 /* in single quotes */
2785#define ARISYNTAX 3 /* in arithmetic */
2786#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002787
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002788#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002789
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002790static int
2791SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002792{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002793 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2794 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2795 /*
2796 * This causes '/' to be prepended with CTLESC in dquoted string,
2797 * making "./file"* treated incorrectly because we feed
2798 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2799 * The "homegrown" glob implementation is okay with that,
2800 * but glibc one isn't. With '/' always treated as CWORD,
2801 * both work fine.
2802 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002803# if ENABLE_ASH_ALIAS
2804 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002805 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002806 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002807 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2808 11, 3 /* "}~" */
2809 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002810# else
2811 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002812 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002813 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002814 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2815 10, 2 /* "}~" */
2816 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002817# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002818 const char *s;
2819 int indx;
2820
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002821 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002822 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002823# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002824 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002825 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002826 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002827# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002828 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002829 /* Cast is purely for paranoia here,
2830 * just in case someone passed signed char to us */
2831 if ((unsigned char)c >= CTL_FIRST
2832 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002833 ) {
2834 return CCTL;
2835 }
2836 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002837 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002838 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002839 indx = syntax_index_table[s - spec_symbls];
2840 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002841 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002842}
2843
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002844#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002845
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002846static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002847 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002848 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2849 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2850 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2851 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2852 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2853 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2854 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2855 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2856 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2857 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2858 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2859 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2881 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2882 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2883 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2884 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2885 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2886 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2887 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2888 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2889 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2890 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2891 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2892 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2893 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2894 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002895/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2896 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002897 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2898 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2899 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2901 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2902 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2903 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2904 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2905 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2909 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2910 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2911 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2912 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2913 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2941 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2942 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2943 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2946 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2974 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2975 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2976 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2977 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2978 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2979 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2980 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2981 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2982 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2983 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2984 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2985 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2986 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2987 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2988 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2989 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2990 /* 141 */ CWORD_CWORD_CWORD_CWORD,
2991 /* 142 */ CWORD_CWORD_CWORD_CWORD,
2992 /* 143 */ CWORD_CWORD_CWORD_CWORD,
2993 /* 144 */ CWORD_CWORD_CWORD_CWORD,
2994 /* 145 */ CWORD_CWORD_CWORD_CWORD,
2995 /* 146 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 147 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 148 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 149 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003105 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003106# if ENABLE_ASH_ALIAS
3107 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3108# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003109};
3110
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003111# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003112
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003113#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003114
Eric Andersen2870d962001-07-02 17:27:21 +00003115
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003116/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003117
Denis Vlasenko131ae172007-02-18 13:00:19 +00003118#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003119
3120#define ALIASINUSE 1
3121#define ALIASDEAD 2
3122
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003123struct alias {
3124 struct alias *next;
3125 char *name;
3126 char *val;
3127 int flag;
3128};
3129
Denis Vlasenko01631112007-12-16 17:20:38 +00003130
3131static struct alias **atab; // [ATABSIZE];
3132#define INIT_G_alias() do { \
3133 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3134} while (0)
3135
Eric Andersen2870d962001-07-02 17:27:21 +00003136
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003137static struct alias **
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02003138__lookupalias(const char *name)
3139{
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003140 unsigned int hashval;
3141 struct alias **app;
3142 const char *p;
3143 unsigned int ch;
3144
3145 p = name;
3146
3147 ch = (unsigned char)*p;
3148 hashval = ch << 4;
3149 while (ch) {
3150 hashval += ch;
3151 ch = (unsigned char)*++p;
3152 }
3153 app = &atab[hashval % ATABSIZE];
3154
3155 for (; *app; app = &(*app)->next) {
3156 if (strcmp(name, (*app)->name) == 0) {
3157 break;
3158 }
3159 }
3160
3161 return app;
3162}
3163
3164static struct alias *
3165lookupalias(const char *name, int check)
3166{
3167 struct alias *ap = *__lookupalias(name);
3168
3169 if (check && ap && (ap->flag & ALIASINUSE))
3170 return NULL;
3171 return ap;
3172}
3173
3174static struct alias *
3175freealias(struct alias *ap)
3176{
3177 struct alias *next;
3178
3179 if (ap->flag & ALIASINUSE) {
3180 ap->flag |= ALIASDEAD;
3181 return ap;
3182 }
3183
3184 next = ap->next;
3185 free(ap->name);
3186 free(ap->val);
3187 free(ap);
3188 return next;
3189}
Eric Andersencb57d552001-06-28 07:25:16 +00003190
Eric Andersenc470f442003-07-28 09:56:35 +00003191static void
3192setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003193{
3194 struct alias *ap, **app;
3195
3196 app = __lookupalias(name);
3197 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003198 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003199 if (ap) {
3200 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003201 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003202 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003203 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003204 ap->flag &= ~ALIASDEAD;
3205 } else {
3206 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003207 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003208 ap->name = ckstrdup(name);
3209 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003210 /*ap->flag = 0; - ckzalloc did it */
3211 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003212 *app = ap;
3213 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003214 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003215}
3216
Eric Andersenc470f442003-07-28 09:56:35 +00003217static int
3218unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003219{
Eric Andersencb57d552001-06-28 07:25:16 +00003220 struct alias **app;
3221
3222 app = __lookupalias(name);
3223
3224 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003225 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003226 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003227 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003228 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003229 }
3230
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003231 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003232}
3233
Eric Andersenc470f442003-07-28 09:56:35 +00003234static void
3235rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003236{
Eric Andersencb57d552001-06-28 07:25:16 +00003237 struct alias *ap, **app;
3238 int i;
3239
Denis Vlasenkob012b102007-02-19 22:43:01 +00003240 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003241 for (i = 0; i < ATABSIZE; i++) {
3242 app = &atab[i];
3243 for (ap = *app; ap; ap = *app) {
3244 *app = freealias(*app);
3245 if (ap == *app) {
3246 app = &ap->next;
3247 }
3248 }
3249 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003250 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003251}
3252
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003253static void
3254printalias(const struct alias *ap)
3255{
3256 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3257}
3258
Eric Andersencb57d552001-06-28 07:25:16 +00003259/*
3260 * TODO - sort output
3261 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003262static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003263aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003264{
3265 char *n, *v;
3266 int ret = 0;
3267 struct alias *ap;
3268
Denis Vlasenko68404f12008-03-17 09:00:54 +00003269 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003270 int i;
3271
Denis Vlasenko68404f12008-03-17 09:00:54 +00003272 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003273 for (ap = atab[i]; ap; ap = ap->next) {
3274 printalias(ap);
3275 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003276 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003277 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003278 }
3279 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003280 v = strchr(n+1, '=');
3281 if (v == NULL) { /* n+1: funny ksh stuff */
3282 ap = *__lookupalias(n);
3283 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003284 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003285 ret = 1;
3286 } else
3287 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003288 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003289 *v++ = '\0';
3290 setalias(n, v);
3291 }
3292 }
3293
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003294 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003295}
3296
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003297static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003298unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003299{
3300 int i;
3301
3302 while ((i = nextopt("a")) != '\0') {
3303 if (i == 'a') {
3304 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003305 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003306 }
3307 }
3308 for (i = 0; *argptr; argptr++) {
3309 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003310 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003311 i = 1;
3312 }
3313 }
3314
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003315 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003316}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003317
Denis Vlasenko131ae172007-02-18 13:00:19 +00003318#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003319
Eric Andersenc470f442003-07-28 09:56:35 +00003320
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003321/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003322#define FORK_FG 0
3323#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003324#define FORK_NOJOB 2
3325
3326/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003327#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3328#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3329#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003330#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003331
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003332/*
3333 * A job structure contains information about a job. A job is either a
3334 * single process or a set of processes contained in a pipeline. In the
3335 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3336 * array of pids.
3337 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003338struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003339 pid_t ps_pid; /* process id */
3340 int ps_status; /* last process status from wait() */
3341 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003342};
3343
3344struct job {
3345 struct procstat ps0; /* status of process */
3346 struct procstat *ps; /* status or processes when more than one */
3347#if JOBS
3348 int stopstatus; /* status of a stopped job */
3349#endif
3350 uint32_t
3351 nprocs: 16, /* number of processes */
3352 state: 8,
3353#define JOBRUNNING 0 /* at least one proc running */
3354#define JOBSTOPPED 1 /* all procs are stopped */
3355#define JOBDONE 2 /* all procs are completed */
3356#if JOBS
3357 sigint: 1, /* job was killed by SIGINT */
3358 jobctl: 1, /* job running under job control */
3359#endif
3360 waited: 1, /* true if this entry has been waited for */
3361 used: 1, /* true if this entry is in used */
3362 changed: 1; /* true if status has changed */
3363 struct job *prev_job; /* previous job */
3364};
3365
Denis Vlasenko68404f12008-03-17 09:00:54 +00003366static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003367static int forkshell(struct job *, union node *, int);
3368static int waitforjob(struct job *);
3369
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003370#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003371enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003372#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003373#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003374static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003375static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003376#endif
3377
3378/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003379 * Ignore a signal.
3380 */
3381static void
3382ignoresig(int signo)
3383{
3384 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3385 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3386 /* No, need to do it */
3387 signal(signo, SIG_IGN);
3388 }
3389 sigmode[signo - 1] = S_HARD_IGN;
3390}
3391
3392/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003393 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003394 */
3395static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003396signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003397{
3398 gotsig[signo - 1] = 1;
3399
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003400 if (signo == SIGINT && !trap[SIGINT]) {
3401 if (!suppress_int) {
3402 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003403 raise_interrupt(); /* does not return */
3404 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003405 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003406 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003407 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003408 }
3409}
3410
3411/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003412 * Set the signal handler for the specified signal. The routine figures
3413 * out what it should be set to.
3414 */
3415static void
3416setsignal(int signo)
3417{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003418 char *t;
3419 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003420 struct sigaction act;
3421
3422 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003423 new_act = S_DFL;
3424 if (t != NULL) { /* trap for this sig is set */
3425 new_act = S_CATCH;
3426 if (t[0] == '\0') /* trap is "": ignore this sig */
3427 new_act = S_IGN;
3428 }
3429
3430 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003431 switch (signo) {
3432 case SIGINT:
3433 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003434 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003435 break;
3436 case SIGQUIT:
3437#if DEBUG
3438 if (debug)
3439 break;
3440#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003441 /* man bash:
3442 * "In all cases, bash ignores SIGQUIT. Non-builtin
3443 * commands run by bash have signal handlers
3444 * set to the values inherited by the shell
3445 * from its parent". */
3446 new_act = S_IGN;
3447 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003448 case SIGTERM:
3449 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003450 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003451 break;
3452#if JOBS
3453 case SIGTSTP:
3454 case SIGTTOU:
3455 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003456 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003457 break;
3458#endif
3459 }
3460 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003461//TODO: if !rootshell, we reset SIGQUIT to DFL,
3462//whereas we have to restore it to what shell got on entry
3463//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003464
3465 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003466 cur_act = *t;
3467 if (cur_act == 0) {
3468 /* current setting is not yet known */
3469 if (sigaction(signo, NULL, &act)) {
3470 /* pretend it worked; maybe we should give a warning,
3471 * but other shells don't. We don't alter sigmode,
3472 * so we retry every time.
3473 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003474 return;
3475 }
3476 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003477 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003478 if (mflag
3479 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3480 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003481 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003482 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003483 }
3484 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003485 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003486 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003487
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003488 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003489 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003490 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003491 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003492 break;
3493 case S_IGN:
3494 act.sa_handler = SIG_IGN;
3495 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003497
3498 /* flags and mask matter only if !DFL and !IGN, but we do it
3499 * for all cases for more deterministic behavior:
3500 */
3501 act.sa_flags = 0;
3502 sigfillset(&act.sa_mask);
3503
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003504 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003505
3506 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003507}
3508
3509/* mode flags for set_curjob */
3510#define CUR_DELETE 2
3511#define CUR_RUNNING 1
3512#define CUR_STOPPED 0
3513
3514/* mode flags for dowait */
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003515#define DOWAIT_NONBLOCK 0
3516#define DOWAIT_BLOCK 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003517
3518#if JOBS
3519/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003520static int initialpgrp; //references:2
3521static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003522#endif
3523/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003524static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003525/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003526static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003528static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003529/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003530static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531
3532static void
3533set_curjob(struct job *jp, unsigned mode)
3534{
3535 struct job *jp1;
3536 struct job **jpp, **curp;
3537
3538 /* first remove from list */
3539 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003540 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003541 jp1 = *jpp;
3542 if (jp1 == jp)
3543 break;
3544 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003545 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003546 *jpp = jp1->prev_job;
3547
3548 /* Then re-insert in correct position */
3549 jpp = curp;
3550 switch (mode) {
3551 default:
3552#if DEBUG
3553 abort();
3554#endif
3555 case CUR_DELETE:
3556 /* job being deleted */
3557 break;
3558 case CUR_RUNNING:
3559 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003560 * put after all stopped jobs.
3561 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003562 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003563 jp1 = *jpp;
3564#if JOBS
3565 if (!jp1 || jp1->state != JOBSTOPPED)
3566#endif
3567 break;
3568 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003569 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003570 /* FALLTHROUGH */
3571#if JOBS
3572 case CUR_STOPPED:
3573#endif
3574 /* newly stopped job - becomes curjob */
3575 jp->prev_job = *jpp;
3576 *jpp = jp;
3577 break;
3578 }
3579}
3580
3581#if JOBS || DEBUG
3582static int
3583jobno(const struct job *jp)
3584{
3585 return jp - jobtab + 1;
3586}
3587#endif
3588
3589/*
3590 * Convert a job name to a job structure.
3591 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003592#if !JOBS
3593#define getjob(name, getctl) getjob(name)
3594#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003595static struct job *
3596getjob(const char *name, int getctl)
3597{
3598 struct job *jp;
3599 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003600 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003601 unsigned num;
3602 int c;
3603 const char *p;
3604 char *(*match)(const char *, const char *);
3605
3606 jp = curjob;
3607 p = name;
3608 if (!p)
3609 goto currentjob;
3610
3611 if (*p != '%')
3612 goto err;
3613
3614 c = *++p;
3615 if (!c)
3616 goto currentjob;
3617
3618 if (!p[1]) {
3619 if (c == '+' || c == '%') {
3620 currentjob:
3621 err_msg = "No current job";
3622 goto check;
3623 }
3624 if (c == '-') {
3625 if (jp)
3626 jp = jp->prev_job;
3627 err_msg = "No previous job";
3628 check:
3629 if (!jp)
3630 goto err;
3631 goto gotit;
3632 }
3633 }
3634
3635 if (is_number(p)) {
3636 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003637 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003638 jp = jobtab + num - 1;
3639 if (jp->used)
3640 goto gotit;
3641 goto err;
3642 }
3643 }
3644
3645 match = prefix;
3646 if (*p == '?') {
3647 match = strstr;
3648 p++;
3649 }
3650
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003651 found = NULL;
3652 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003653 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003654 if (found)
3655 goto err;
3656 found = jp;
3657 err_msg = "%s: ambiguous";
3658 }
3659 jp = jp->prev_job;
3660 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003661 if (!found)
3662 goto err;
3663 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003664
3665 gotit:
3666#if JOBS
3667 err_msg = "job %s not created under job control";
3668 if (getctl && jp->jobctl == 0)
3669 goto err;
3670#endif
3671 return jp;
3672 err:
3673 ash_msg_and_raise_error(err_msg, name);
3674}
3675
3676/*
3677 * Mark a job structure as unused.
3678 */
3679static void
3680freejob(struct job *jp)
3681{
3682 struct procstat *ps;
3683 int i;
3684
3685 INT_OFF;
3686 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003687 if (ps->ps_cmd != nullstr)
3688 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003689 }
3690 if (jp->ps != &jp->ps0)
3691 free(jp->ps);
3692 jp->used = 0;
3693 set_curjob(jp, CUR_DELETE);
3694 INT_ON;
3695}
3696
3697#if JOBS
3698static void
3699xtcsetpgrp(int fd, pid_t pgrp)
3700{
3701 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003702 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003703}
3704
3705/*
3706 * Turn job control on and off.
3707 *
3708 * Note: This code assumes that the third arg to ioctl is a character
3709 * pointer, which is true on Berkeley systems but not System V. Since
3710 * System V doesn't have job control yet, this isn't a problem now.
3711 *
3712 * Called with interrupts off.
3713 */
3714static void
3715setjobctl(int on)
3716{
3717 int fd;
3718 int pgrp;
3719
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003720 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003721 return;
3722 if (on) {
3723 int ofd;
3724 ofd = fd = open(_PATH_TTY, O_RDWR);
3725 if (fd < 0) {
3726 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3727 * That sometimes helps to acquire controlling tty.
3728 * Obviously, a workaround for bugs when someone
3729 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003730 fd = 2;
3731 while (!isatty(fd))
3732 if (--fd < 0)
3733 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003734 }
Denys Vlasenko64774602016-10-26 15:24:30 +02003735 /* fd is a tty at this point */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003736 fd = fcntl(fd, F_DUPFD, 10);
Denys Vlasenko64774602016-10-26 15:24:30 +02003737 if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, dont */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003738 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003739 if (fd < 0)
Denys Vlasenko64774602016-10-26 15:24:30 +02003740 goto out; /* F_DUPFD failed */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003741 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003742 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003743 pgrp = tcgetpgrp(fd);
3744 if (pgrp < 0) {
3745 out:
3746 ash_msg("can't access tty; job control turned off");
3747 mflag = on = 0;
3748 goto close;
3749 }
3750 if (pgrp == getpgrp())
3751 break;
3752 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003753 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003754 initialpgrp = pgrp;
3755
3756 setsignal(SIGTSTP);
3757 setsignal(SIGTTOU);
3758 setsignal(SIGTTIN);
3759 pgrp = rootpid;
3760 setpgid(0, pgrp);
3761 xtcsetpgrp(fd, pgrp);
3762 } else {
3763 /* turning job control off */
3764 fd = ttyfd;
3765 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003766 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003767 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003768 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003769 setpgid(0, pgrp);
3770 setsignal(SIGTSTP);
3771 setsignal(SIGTTOU);
3772 setsignal(SIGTTIN);
3773 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003774 if (fd >= 0)
3775 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003776 fd = -1;
3777 }
3778 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003779 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003780}
3781
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003782static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003783killcmd(int argc, char **argv)
3784{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003785 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003786 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003787 do {
3788 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003789 /*
3790 * "kill %N" - job kill
3791 * Converting to pgrp / pid kill
3792 */
3793 struct job *jp;
3794 char *dst;
3795 int j, n;
3796
3797 jp = getjob(argv[i], 0);
3798 /*
3799 * In jobs started under job control, we signal
3800 * entire process group by kill -PGRP_ID.
3801 * This happens, f.e., in interactive shell.
3802 *
3803 * Otherwise, we signal each child via
3804 * kill PID1 PID2 PID3.
3805 * Testcases:
3806 * sh -c 'sleep 1|sleep 1 & kill %1'
3807 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3808 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3809 */
3810 n = jp->nprocs; /* can't be 0 (I hope) */
3811 if (jp->jobctl)
3812 n = 1;
3813 dst = alloca(n * sizeof(int)*4);
3814 argv[i] = dst;
3815 for (j = 0; j < n; j++) {
3816 struct procstat *ps = &jp->ps[j];
3817 /* Skip non-running and not-stopped members
3818 * (i.e. dead members) of the job
3819 */
3820 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3821 continue;
3822 /*
3823 * kill_main has matching code to expect
3824 * leading space. Needed to not confuse
3825 * negative pids with "kill -SIGNAL_NO" syntax
3826 */
3827 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3828 }
3829 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003830 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003831 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003832 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003833 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003834}
3835
3836static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003837showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003838{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003839 struct procstat *ps;
3840 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003841
Denys Vlasenko285ad152009-12-04 23:02:27 +01003842 psend = jp->ps + jp->nprocs;
3843 for (ps = jp->ps + 1; ps < psend; ps++)
3844 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003845 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003846 flush_stdout_stderr();
3847}
3848
3849
3850static int
3851restartjob(struct job *jp, int mode)
3852{
3853 struct procstat *ps;
3854 int i;
3855 int status;
3856 pid_t pgid;
3857
3858 INT_OFF;
3859 if (jp->state == JOBDONE)
3860 goto out;
3861 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003862 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003863 if (mode == FORK_FG)
3864 xtcsetpgrp(ttyfd, pgid);
3865 killpg(pgid, SIGCONT);
3866 ps = jp->ps;
3867 i = jp->nprocs;
3868 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003869 if (WIFSTOPPED(ps->ps_status)) {
3870 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003871 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003872 ps++;
3873 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003874 out:
3875 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3876 INT_ON;
3877 return status;
3878}
3879
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003880static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003881fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003882{
3883 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003884 int mode;
3885 int retval;
3886
3887 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3888 nextopt(nullstr);
3889 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003890 do {
3891 jp = getjob(*argv, 1);
3892 if (mode == FORK_BG) {
3893 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003894 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003895 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003896 out1str(jp->ps[0].ps_cmd);
3897 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003898 retval = restartjob(jp, mode);
3899 } while (*argv && *++argv);
3900 return retval;
3901}
3902#endif
3903
3904static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003905sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003906{
3907 int col;
3908 int st;
3909
3910 col = 0;
3911 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003912 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003913 st = WSTOPSIG(status);
3914 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003915 st = WTERMSIG(status);
3916 if (sigonly) {
3917 if (st == SIGINT || st == SIGPIPE)
3918 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003919 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003920 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003921 }
3922 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003923//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003924 col = fmtstr(s, 32, strsignal(st));
3925 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003926 strcpy(s + col, " (core dumped)");
3927 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003928 }
3929 } else if (!sigonly) {
3930 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003931 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003932 }
3933 out:
3934 return col;
3935}
3936
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003937static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003938dowait(int block, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003939{
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003940 int wait_flags;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003941 int pid;
3942 int status;
3943 struct job *jp;
3944 struct job *thisjob;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003945
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003946 TRACE(("dowait(0x%x) called\n", block));
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003947
3948 /* Do a wait system call. If job control is compiled in, we accept
Denys Vlasenkob543bda2016-10-27 20:08:28 +02003949 * stopped processes.
3950 * NB: _not_ safe_waitpid, we need to detect EINTR.
3951 */
3952 wait_flags = 0;
3953 if (block == DOWAIT_NONBLOCK)
3954 wait_flags = WNOHANG;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003955 if (doing_jobctl)
3956 wait_flags |= WUNTRACED;
3957 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003958 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3959 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003960 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003961 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003962
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003963 INT_OFF;
3964 thisjob = NULL;
3965 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003966 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003967 struct procstat *ps;
3968 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003969 if (jp->state == JOBDONE)
3970 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003971 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003972 ps = jp->ps;
3973 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003974 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003975 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003976 TRACE(("Job %d: changing status of proc %d "
3977 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003978 jobno(jp), pid, ps->ps_status, status));
3979 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003980 thisjob = jp;
3981 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003982 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003983 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003984#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003985 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003986 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003987 if (WIFSTOPPED(ps->ps_status)) {
3988 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003989 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003990 }
3991#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01003992 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003993 if (!thisjob)
3994 continue;
3995
3996 /* Found the job where one of its processes changed its state.
3997 * Is there at least one live and running process in this job? */
3998 if (jobstate != JOBRUNNING) {
3999 /* No. All live processes in the job are stopped
4000 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4001 */
4002 thisjob->changed = 1;
4003 if (thisjob->state != jobstate) {
4004 TRACE(("Job %d: changing state from %d to %d\n",
4005 jobno(thisjob), thisjob->state, jobstate));
4006 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004007#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004008 if (jobstate == JOBSTOPPED)
4009 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004010#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004011 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004013 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004014 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004015 /* The process wasn't found in job list */
4016 if (JOBS && !WIFSTOPPED(status))
4017 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004018 out:
4019 INT_ON;
4020
4021 if (thisjob && thisjob == job) {
4022 char s[48 + 1];
4023 int len;
4024
Denys Vlasenko9c541002015-10-07 15:44:36 +02004025 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004026 if (len) {
4027 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004028 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004029 out2str(s);
4030 }
4031 }
4032 return pid;
4033}
4034
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004035static int
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004036blocking_dowait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004037{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004038 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004039 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004040 raise_exception(EXSIG);
4041 return pid;
4042}
4043
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004044#if JOBS
4045static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004046showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004047{
4048 struct procstat *ps;
4049 struct procstat *psend;
4050 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004051 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004052 char s[16 + 16 + 48];
4053 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004054
4055 ps = jp->ps;
4056
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004057 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004058 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004059 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004060 return;
4061 }
4062
4063 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004064 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004065
4066 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004067 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004068 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004069 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004070
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004071 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004072 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073
4074 psend = ps + jp->nprocs;
4075
4076 if (jp->state == JOBRUNNING) {
4077 strcpy(s + col, "Running");
4078 col += sizeof("Running") - 1;
4079 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004080 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004081 if (jp->state == JOBSTOPPED)
4082 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004083 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004084 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004085 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004086
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004087 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4088 * or prints several "PID | <cmdN>" lines,
4089 * depending on SHOW_PIDS bit.
4090 * We do not print status of individual processes
4091 * between PID and <cmdN>. bash does it, but not very well:
4092 * first line shows overall job status, not process status,
4093 * making it impossible to know 1st process status.
4094 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004095 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004096 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004097 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004098 s[0] = '\0';
4099 col = 33;
4100 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004101 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004102 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004103 fprintf(out, "%s%*c%s%s",
4104 s,
4105 33 - col >= 0 ? 33 - col : 0, ' ',
4106 ps == jp->ps ? "" : "| ",
4107 ps->ps_cmd
4108 );
4109 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004110 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004111
4112 jp->changed = 0;
4113
4114 if (jp->state == JOBDONE) {
4115 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4116 freejob(jp);
4117 }
4118}
4119
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004120/*
4121 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4122 * statuses have changed since the last call to showjobs.
4123 */
4124static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004125showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004126{
4127 struct job *jp;
4128
Denys Vlasenko883cea42009-07-11 15:31:59 +02004129 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004130
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004131 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004132 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004133 continue;
4134
4135 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004136 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004137 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004138 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004139 }
4140}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004141
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004142static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004143jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004144{
4145 int mode, m;
4146
4147 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004148 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004149 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004150 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004151 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004152 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004153 }
4154
4155 argv = argptr;
4156 if (*argv) {
4157 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004158 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004159 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004160 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004161 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004162 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004163
4164 return 0;
4165}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004166#endif /* JOBS */
4167
Michael Abbott359da5e2009-12-04 23:03:29 +01004168/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004169static int
4170getstatus(struct job *job)
4171{
4172 int status;
4173 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004174 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004175
Michael Abbott359da5e2009-12-04 23:03:29 +01004176 /* Fetch last member's status */
4177 ps = job->ps + job->nprocs - 1;
4178 status = ps->ps_status;
4179 if (pipefail) {
4180 /* "set -o pipefail" mode: use last _nonzero_ status */
4181 while (status == 0 && --ps >= job->ps)
4182 status = ps->ps_status;
4183 }
4184
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004185 retval = WEXITSTATUS(status);
4186 if (!WIFEXITED(status)) {
4187#if JOBS
4188 retval = WSTOPSIG(status);
4189 if (!WIFSTOPPED(status))
4190#endif
4191 {
4192 /* XXX: limits number of signals */
4193 retval = WTERMSIG(status);
4194#if JOBS
4195 if (retval == SIGINT)
4196 job->sigint = 1;
4197#endif
4198 }
4199 retval += 128;
4200 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004201 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004202 jobno(job), job->nprocs, status, retval));
4203 return retval;
4204}
4205
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004206static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004207waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004208{
4209 struct job *job;
4210 int retval;
4211 struct job *jp;
4212
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004213 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004214 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004215
4216 nextopt(nullstr);
4217 retval = 0;
4218
4219 argv = argptr;
4220 if (!*argv) {
4221 /* wait for all jobs */
4222 for (;;) {
4223 jp = curjob;
4224 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004225 if (!jp) /* no running procs */
4226 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004227 if (jp->state == JOBRUNNING)
4228 break;
4229 jp->waited = 1;
4230 jp = jp->prev_job;
4231 }
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004232 blocking_dowait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004233 /* man bash:
4234 * "When bash is waiting for an asynchronous command via
4235 * the wait builtin, the reception of a signal for which a trap
4236 * has been set will cause the wait builtin to return immediately
4237 * with an exit status greater than 128, immediately after which
4238 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004239 *
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004240 * blocking_dowait_with_raise_on_sig raises signal handlers
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004241 * if it gets no pid (pid < 0). However,
4242 * if child sends us a signal *and immediately exits*,
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004243 * blocking_dowait_with_raise_on_sig gets pid > 0
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004244 * and does not handle pending_sig. Check this case: */
4245 if (pending_sig)
4246 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004247 }
4248 }
4249
4250 retval = 127;
4251 do {
4252 if (**argv != '%') {
4253 pid_t pid = number(*argv);
4254 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004255 while (1) {
4256 if (!job)
4257 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004258 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004259 break;
4260 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004261 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004262 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004263 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004264 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004265 /* loop until process terminated or stopped */
4266 while (job->state == JOBRUNNING)
Denys Vlasenkob543bda2016-10-27 20:08:28 +02004267 blocking_dowait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004268 job->waited = 1;
4269 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004270 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004271 } while (*++argv);
4272
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004273 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004274 return retval;
4275}
4276
4277static struct job *
4278growjobtab(void)
4279{
4280 size_t len;
4281 ptrdiff_t offset;
4282 struct job *jp, *jq;
4283
4284 len = njobs * sizeof(*jp);
4285 jq = jobtab;
4286 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4287
4288 offset = (char *)jp - (char *)jq;
4289 if (offset) {
4290 /* Relocate pointers */
4291 size_t l = len;
4292
4293 jq = (struct job *)((char *)jq + l);
4294 while (l) {
4295 l -= sizeof(*jp);
4296 jq--;
4297#define joff(p) ((struct job *)((char *)(p) + l))
4298#define jmove(p) (p) = (void *)((char *)(p) + offset)
4299 if (joff(jp)->ps == &jq->ps0)
4300 jmove(joff(jp)->ps);
4301 if (joff(jp)->prev_job)
4302 jmove(joff(jp)->prev_job);
4303 }
4304 if (curjob)
4305 jmove(curjob);
4306#undef joff
4307#undef jmove
4308 }
4309
4310 njobs += 4;
4311 jobtab = jp;
4312 jp = (struct job *)((char *)jp + len);
4313 jq = jp + 3;
4314 do {
4315 jq->used = 0;
4316 } while (--jq >= jp);
4317 return jp;
4318}
4319
4320/*
4321 * Return a new job structure.
4322 * Called with interrupts off.
4323 */
4324static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004325makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004326{
4327 int i;
4328 struct job *jp;
4329
4330 for (i = njobs, jp = jobtab; ; jp++) {
4331 if (--i < 0) {
4332 jp = growjobtab();
4333 break;
4334 }
4335 if (jp->used == 0)
4336 break;
4337 if (jp->state != JOBDONE || !jp->waited)
4338 continue;
4339#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004340 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004341 continue;
4342#endif
4343 freejob(jp);
4344 break;
4345 }
4346 memset(jp, 0, sizeof(*jp));
4347#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004348 /* jp->jobctl is a bitfield.
4349 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004350 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004351 jp->jobctl = 1;
4352#endif
4353 jp->prev_job = curjob;
4354 curjob = jp;
4355 jp->used = 1;
4356 jp->ps = &jp->ps0;
4357 if (nprocs > 1) {
4358 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4359 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004360 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004361 jobno(jp)));
4362 return jp;
4363}
4364
4365#if JOBS
4366/*
4367 * Return a string identifying a command (to be printed by the
4368 * jobs command).
4369 */
4370static char *cmdnextc;
4371
4372static void
4373cmdputs(const char *s)
4374{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004375 static const char vstype[VSTYPE + 1][3] = {
4376 "", "}", "-", "+", "?", "=",
4377 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004378 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004379 };
4380
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004381 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004382 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004383 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004384 unsigned char c;
4385 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004386 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004387
Denys Vlasenko46a14772009-12-10 21:27:13 +01004388 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004389 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4390 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004391 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004392 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004393 switch (c) {
4394 case CTLESC:
4395 c = *p++;
4396 break;
4397 case CTLVAR:
4398 subtype = *p++;
4399 if ((subtype & VSTYPE) == VSLENGTH)
4400 str = "${#";
4401 else
4402 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004403 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004404 case CTLENDVAR:
4405 str = "\"}" + !(quoted & 1);
4406 quoted >>= 1;
4407 subtype = 0;
4408 goto dostr;
4409 case CTLBACKQ:
4410 str = "$(...)";
4411 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004412#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004413 case CTLARI:
4414 str = "$((";
4415 goto dostr;
4416 case CTLENDARI:
4417 str = "))";
4418 goto dostr;
4419#endif
4420 case CTLQUOTEMARK:
4421 quoted ^= 1;
4422 c = '"';
4423 break;
4424 case '=':
4425 if (subtype == 0)
4426 break;
4427 if ((subtype & VSTYPE) != VSNORMAL)
4428 quoted <<= 1;
4429 str = vstype[subtype & VSTYPE];
4430 if (subtype & VSNUL)
4431 c = ':';
4432 else
4433 goto checkstr;
4434 break;
4435 case '\'':
4436 case '\\':
4437 case '"':
4438 case '$':
4439 /* These can only happen inside quotes */
4440 cc[0] = c;
4441 str = cc;
4442 c = '\\';
4443 break;
4444 default:
4445 break;
4446 }
4447 USTPUTC(c, nextc);
4448 checkstr:
4449 if (!str)
4450 continue;
4451 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004452 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004453 USTPUTC(c, nextc);
4454 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004455 } /* while *p++ not NUL */
4456
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004457 if (quoted & 1) {
4458 USTPUTC('"', nextc);
4459 }
4460 *nextc = 0;
4461 cmdnextc = nextc;
4462}
4463
4464/* cmdtxt() and cmdlist() call each other */
4465static void cmdtxt(union node *n);
4466
4467static void
4468cmdlist(union node *np, int sep)
4469{
4470 for (; np; np = np->narg.next) {
4471 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004472 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004473 cmdtxt(np);
4474 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004475 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004476 }
4477}
4478
4479static void
4480cmdtxt(union node *n)
4481{
4482 union node *np;
4483 struct nodelist *lp;
4484 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004485
4486 if (!n)
4487 return;
4488 switch (n->type) {
4489 default:
4490#if DEBUG
4491 abort();
4492#endif
4493 case NPIPE:
4494 lp = n->npipe.cmdlist;
4495 for (;;) {
4496 cmdtxt(lp->n);
4497 lp = lp->next;
4498 if (!lp)
4499 break;
4500 cmdputs(" | ");
4501 }
4502 break;
4503 case NSEMI:
4504 p = "; ";
4505 goto binop;
4506 case NAND:
4507 p = " && ";
4508 goto binop;
4509 case NOR:
4510 p = " || ";
4511 binop:
4512 cmdtxt(n->nbinary.ch1);
4513 cmdputs(p);
4514 n = n->nbinary.ch2;
4515 goto donode;
4516 case NREDIR:
4517 case NBACKGND:
4518 n = n->nredir.n;
4519 goto donode;
4520 case NNOT:
4521 cmdputs("!");
4522 n = n->nnot.com;
4523 donode:
4524 cmdtxt(n);
4525 break;
4526 case NIF:
4527 cmdputs("if ");
4528 cmdtxt(n->nif.test);
4529 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004530 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004531 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004532 cmdputs("; else ");
4533 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004534 } else {
4535 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004536 }
4537 p = "; fi";
4538 goto dotail;
4539 case NSUBSHELL:
4540 cmdputs("(");
4541 n = n->nredir.n;
4542 p = ")";
4543 goto dotail;
4544 case NWHILE:
4545 p = "while ";
4546 goto until;
4547 case NUNTIL:
4548 p = "until ";
4549 until:
4550 cmdputs(p);
4551 cmdtxt(n->nbinary.ch1);
4552 n = n->nbinary.ch2;
4553 p = "; done";
4554 dodo:
4555 cmdputs("; do ");
4556 dotail:
4557 cmdtxt(n);
4558 goto dotail2;
4559 case NFOR:
4560 cmdputs("for ");
4561 cmdputs(n->nfor.var);
4562 cmdputs(" in ");
4563 cmdlist(n->nfor.args, 1);
4564 n = n->nfor.body;
4565 p = "; done";
4566 goto dodo;
4567 case NDEFUN:
4568 cmdputs(n->narg.text);
4569 p = "() { ... }";
4570 goto dotail2;
4571 case NCMD:
4572 cmdlist(n->ncmd.args, 1);
4573 cmdlist(n->ncmd.redirect, 0);
4574 break;
4575 case NARG:
4576 p = n->narg.text;
4577 dotail2:
4578 cmdputs(p);
4579 break;
4580 case NHERE:
4581 case NXHERE:
4582 p = "<<...";
4583 goto dotail2;
4584 case NCASE:
4585 cmdputs("case ");
4586 cmdputs(n->ncase.expr->narg.text);
4587 cmdputs(" in ");
4588 for (np = n->ncase.cases; np; np = np->nclist.next) {
4589 cmdtxt(np->nclist.pattern);
4590 cmdputs(") ");
4591 cmdtxt(np->nclist.body);
4592 cmdputs(";; ");
4593 }
4594 p = "esac";
4595 goto dotail2;
4596 case NTO:
4597 p = ">";
4598 goto redir;
4599 case NCLOBBER:
4600 p = ">|";
4601 goto redir;
4602 case NAPPEND:
4603 p = ">>";
4604 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004605#if ENABLE_ASH_BASH_COMPAT
4606 case NTO2:
4607#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004608 case NTOFD:
4609 p = ">&";
4610 goto redir;
4611 case NFROM:
4612 p = "<";
4613 goto redir;
4614 case NFROMFD:
4615 p = "<&";
4616 goto redir;
4617 case NFROMTO:
4618 p = "<>";
4619 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004620 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004621 cmdputs(p);
4622 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004623 cmdputs(utoa(n->ndup.dupfd));
4624 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004625 }
4626 n = n->nfile.fname;
4627 goto donode;
4628 }
4629}
4630
4631static char *
4632commandtext(union node *n)
4633{
4634 char *name;
4635
4636 STARTSTACKSTR(cmdnextc);
4637 cmdtxt(n);
4638 name = stackblock();
Denys Vlasenko6a94cee2016-10-25 17:40:25 +02004639 TRACE(("commandtext: name %p, end %p\n", name, cmdnextc));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004640 return ckstrdup(name);
4641}
4642#endif /* JOBS */
4643
4644/*
4645 * Fork off a subshell. If we are doing job control, give the subshell its
4646 * own process group. Jp is a job structure that the job is to be added to.
4647 * N is the command that will be evaluated by the child. Both jp and n may
4648 * be NULL. The mode parameter can be one of the following:
4649 * FORK_FG - Fork off a foreground process.
4650 * FORK_BG - Fork off a background process.
4651 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4652 * process group even if job control is on.
4653 *
4654 * When job control is turned off, background processes have their standard
4655 * input redirected to /dev/null (except for the second and later processes
4656 * in a pipeline).
4657 *
4658 * Called with interrupts off.
4659 */
4660/*
4661 * Clear traps on a fork.
4662 */
4663static void
4664clear_traps(void)
4665{
4666 char **tp;
4667
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004668 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004669 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004670 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004671 if (trap_ptr == trap)
4672 free(*tp);
4673 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004674 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004675 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004676 setsignal(tp - trap);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004677 }
4678 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004679 may_have_traps = 0;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +02004680 INT_ON;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004681}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004682
4683/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004684static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004685
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004686/* Called after fork(), in child */
Denys Vlasenko70392332016-10-27 02:31:55 +02004687/* jp and n are NULL when called by openhere() for heredoc support */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004688static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004689forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004690{
4691 int oldlvl;
4692
4693 TRACE(("Child shell %d\n", getpid()));
4694 oldlvl = shlvl;
4695 shlvl++;
4696
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004697 /* man bash: "Non-builtin commands run by bash have signal handlers
4698 * set to the values inherited by the shell from its parent".
4699 * Do we do it correctly? */
4700
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004701 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004702
4703 if (mode == FORK_NOJOB /* is it `xxx` ? */
4704 && n && n->type == NCMD /* is it single cmd? */
4705 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004706 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004707 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4708 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4709 ) {
4710 TRACE(("Trap hack\n"));
4711 /* Awful hack for `trap` or $(trap).
4712 *
4713 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4714 * contains an example where "trap" is executed in a subshell:
4715 *
4716 * save_traps=$(trap)
4717 * ...
4718 * eval "$save_traps"
4719 *
4720 * Standard does not say that "trap" in subshell shall print
4721 * parent shell's traps. It only says that its output
4722 * must have suitable form, but then, in the above example
4723 * (which is not supposed to be normative), it implies that.
4724 *
4725 * bash (and probably other shell) does implement it
4726 * (traps are reset to defaults, but "trap" still shows them),
4727 * but as a result, "trap" logic is hopelessly messed up:
4728 *
4729 * # trap
4730 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4731 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4732 * # true | trap <--- trap is in subshell - no output (ditto)
4733 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4734 * trap -- 'echo Ho' SIGWINCH
4735 * # echo `(trap)` <--- in subshell in subshell - output
4736 * trap -- 'echo Ho' SIGWINCH
4737 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4738 * trap -- 'echo Ho' SIGWINCH
4739 *
4740 * The rules when to forget and when to not forget traps
4741 * get really complex and nonsensical.
4742 *
4743 * Our solution: ONLY bare $(trap) or `trap` is special.
4744 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004745 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004746 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004747 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004748 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004749 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004750#if JOBS
4751 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004752 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004753 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004754 pid_t pgrp;
4755
4756 if (jp->nprocs == 0)
4757 pgrp = getpid();
4758 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004759 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004760 /* this can fail because we are doing it in the parent also */
4761 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004762 if (mode == FORK_FG)
4763 xtcsetpgrp(ttyfd, pgrp);
4764 setsignal(SIGTSTP);
4765 setsignal(SIGTTOU);
4766 } else
4767#endif
4768 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004769 /* man bash: "When job control is not in effect,
4770 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004771 ignoresig(SIGINT);
4772 ignoresig(SIGQUIT);
4773 if (jp->nprocs == 0) {
4774 close(0);
4775 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004776 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004777 }
4778 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004779 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004780 if (iflag) { /* why if iflag only? */
4781 setsignal(SIGINT);
4782 setsignal(SIGTERM);
4783 }
4784 /* man bash:
4785 * "In all cases, bash ignores SIGQUIT. Non-builtin
4786 * commands run by bash have signal handlers
4787 * set to the values inherited by the shell
4788 * from its parent".
4789 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004790 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004791 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004792#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004793 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004794 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004795 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004796 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004797 /* "jobs": we do not want to clear job list for it,
4798 * instead we remove only _its_ own_ job from job list.
4799 * This makes "jobs .... | cat" more useful.
4800 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004801 freejob(curjob);
4802 return;
4803 }
4804#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004805 for (jp = curjob; jp; jp = jp->prev_job)
4806 freejob(jp);
4807 jobless = 0;
4808}
4809
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004810/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004811#if !JOBS
4812#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4813#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004814static void
4815forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4816{
4817 TRACE(("In parent shell: child = %d\n", pid));
4818 if (!jp) {
Denys Vlasenko70392332016-10-27 02:31:55 +02004819 /* jp is NULL when called by openhere() for heredoc support */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004820 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4821 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004822 jobless++;
4823 return;
4824 }
4825#if JOBS
4826 if (mode != FORK_NOJOB && jp->jobctl) {
4827 int pgrp;
4828
4829 if (jp->nprocs == 0)
4830 pgrp = pid;
4831 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004832 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004833 /* This can fail because we are doing it in the child also */
4834 setpgid(pid, pgrp);
4835 }
4836#endif
4837 if (mode == FORK_BG) {
4838 backgndpid = pid; /* set $! */
4839 set_curjob(jp, CUR_RUNNING);
4840 }
4841 if (jp) {
4842 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004843 ps->ps_pid = pid;
4844 ps->ps_status = -1;
4845 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004846#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004847 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004848 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004849#endif
4850 }
4851}
4852
Denys Vlasenko70392332016-10-27 02:31:55 +02004853/* jp and n are NULL when called by openhere() for heredoc support */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004854static int
4855forkshell(struct job *jp, union node *n, int mode)
4856{
4857 int pid;
4858
4859 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4860 pid = fork();
4861 if (pid < 0) {
4862 TRACE(("Fork failed, errno=%d", errno));
4863 if (jp)
4864 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004865 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004866 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004867 if (pid == 0) {
4868 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004869 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004870 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004871 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004872 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004873 return pid;
4874}
4875
4876/*
4877 * Wait for job to finish.
4878 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004879 * Under job control we have the problem that while a child process
4880 * is running interrupts generated by the user are sent to the child
4881 * but not to the shell. This means that an infinite loop started by
4882 * an interactive user may be hard to kill. With job control turned off,
4883 * an interactive user may place an interactive program inside a loop.
4884 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004885 * these interrupts to also abort the loop. The approach we take here
4886 * is to have the shell ignore interrupt signals while waiting for a
4887 * foreground process to terminate, and then send itself an interrupt
4888 * signal if the child process was terminated by an interrupt signal.
4889 * Unfortunately, some programs want to do a bit of cleanup and then
4890 * exit on interrupt; unless these processes terminate themselves by
4891 * sending a signal to themselves (instead of calling exit) they will
4892 * confuse this approach.
4893 *
4894 * Called with interrupts off.
4895 */
4896static int
4897waitforjob(struct job *jp)
4898{
4899 int st;
4900
4901 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004902
4903 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004904 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004905 /* In non-interactive shells, we _can_ get
4906 * a keyboard signal here and be EINTRed,
4907 * but we just loop back, waiting for command to complete.
4908 *
4909 * man bash:
4910 * "If bash is waiting for a command to complete and receives
4911 * a signal for which a trap has been set, the trap
4912 * will not be executed until the command completes."
4913 *
4914 * Reality is that even if trap is not set, bash
4915 * will not act on the signal until command completes.
4916 * Try this. sleep5intoff.c:
4917 * #include <signal.h>
4918 * #include <unistd.h>
4919 * int main() {
4920 * sigset_t set;
4921 * sigemptyset(&set);
4922 * sigaddset(&set, SIGINT);
4923 * sigaddset(&set, SIGQUIT);
4924 * sigprocmask(SIG_BLOCK, &set, NULL);
4925 * sleep(5);
4926 * return 0;
4927 * }
4928 * $ bash -c './sleep5intoff; echo hi'
4929 * ^C^C^C^C <--- pressing ^C once a second
4930 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004931 * $ bash -c './sleep5intoff; echo hi'
4932 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4933 * $ _
4934 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004935 dowait(DOWAIT_BLOCK, jp);
4936 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004937 INT_ON;
4938
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004939 st = getstatus(jp);
4940#if JOBS
4941 if (jp->jobctl) {
4942 xtcsetpgrp(ttyfd, rootpid);
4943 /*
4944 * This is truly gross.
4945 * If we're doing job control, then we did a TIOCSPGRP which
4946 * caused us (the shell) to no longer be in the controlling
4947 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4948 * intuit from the subprocess exit status whether a SIGINT
4949 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4950 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004951 if (jp->sigint) /* TODO: do the same with all signals */
4952 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004953 }
4954 if (jp->state == JOBDONE)
4955#endif
4956 freejob(jp);
4957 return st;
4958}
4959
4960/*
4961 * return 1 if there are stopped jobs, otherwise 0
4962 */
4963static int
4964stoppedjobs(void)
4965{
4966 struct job *jp;
4967 int retval;
4968
4969 retval = 0;
4970 if (job_warning)
4971 goto out;
4972 jp = curjob;
4973 if (jp && jp->state == JOBSTOPPED) {
4974 out2str("You have stopped jobs.\n");
4975 job_warning = 2;
4976 retval++;
4977 }
4978 out:
4979 return retval;
4980}
4981
4982
Denys Vlasenko70392332016-10-27 02:31:55 +02004983/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004984 * Code for dealing with input/output redirection.
4985 */
4986
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01004987#undef EMPTY
4988#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004989#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00004990#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004991
4992/*
4993 * Open a file in noclobber mode.
4994 * The code was copied from bash.
4995 */
4996static int
4997noclobberopen(const char *fname)
4998{
4999 int r, fd;
5000 struct stat finfo, finfo2;
5001
5002 /*
5003 * If the file exists and is a regular file, return an error
5004 * immediately.
5005 */
5006 r = stat(fname, &finfo);
5007 if (r == 0 && S_ISREG(finfo.st_mode)) {
5008 errno = EEXIST;
5009 return -1;
5010 }
5011
5012 /*
5013 * If the file was not present (r != 0), make sure we open it
5014 * exclusively so that if it is created before we open it, our open
5015 * will fail. Make sure that we do not truncate an existing file.
5016 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5017 * file was not a regular file, we leave O_EXCL off.
5018 */
5019 if (r != 0)
5020 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5021 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5022
5023 /* If the open failed, return the file descriptor right away. */
5024 if (fd < 0)
5025 return fd;
5026
5027 /*
5028 * OK, the open succeeded, but the file may have been changed from a
5029 * non-regular file to a regular file between the stat and the open.
5030 * We are assuming that the O_EXCL open handles the case where FILENAME
5031 * did not exist and is symlinked to an existing file between the stat
5032 * and open.
5033 */
5034
5035 /*
5036 * If we can open it and fstat the file descriptor, and neither check
5037 * revealed that it was a regular file, and the file has not been
5038 * replaced, return the file descriptor.
5039 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005040 if (fstat(fd, &finfo2) == 0
5041 && !S_ISREG(finfo2.st_mode)
5042 && finfo.st_dev == finfo2.st_dev
5043 && finfo.st_ino == finfo2.st_ino
5044 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005045 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005046 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005047
5048 /* The file has been replaced. badness. */
5049 close(fd);
5050 errno = EEXIST;
5051 return -1;
5052}
5053
5054/*
5055 * Handle here documents. Normally we fork off a process to write the
5056 * data to a pipe. If the document is short, we can stuff the data in
5057 * the pipe without forking.
5058 */
5059/* openhere needs this forward reference */
5060static void expandhere(union node *arg, int fd);
5061static int
5062openhere(union node *redir)
5063{
5064 int pip[2];
5065 size_t len = 0;
5066
5067 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005068 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005069 if (redir->type == NHERE) {
5070 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005071 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005072 full_write(pip[1], redir->nhere.doc->narg.text, len);
5073 goto out;
5074 }
5075 }
5076 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005077 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005078 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005079 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5080 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5081 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5082 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005083 signal(SIGPIPE, SIG_DFL);
5084 if (redir->type == NHERE)
5085 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005086 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005087 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005088 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005089 }
5090 out:
5091 close(pip[1]);
5092 return pip[0];
5093}
5094
5095static int
5096openredirect(union node *redir)
5097{
5098 char *fname;
5099 int f;
5100
5101 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005102/* Can't happen, our single caller does this itself */
5103// case NTOFD:
5104// case NFROMFD:
5105// return -1;
5106 case NHERE:
5107 case NXHERE:
5108 return openhere(redir);
5109 }
5110
5111 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5112 * allocated space. Do it only when we know it is safe.
5113 */
5114 fname = redir->nfile.expfname;
5115
5116 switch (redir->nfile.type) {
5117 default:
5118#if DEBUG
5119 abort();
5120#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005121 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005122 f = open(fname, O_RDONLY);
5123 if (f < 0)
5124 goto eopen;
5125 break;
5126 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005127 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005128 if (f < 0)
5129 goto ecreate;
5130 break;
5131 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005132#if ENABLE_ASH_BASH_COMPAT
5133 case NTO2:
5134#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005135 /* Take care of noclobber mode. */
5136 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005137 f = noclobberopen(fname);
5138 if (f < 0)
5139 goto ecreate;
5140 break;
5141 }
5142 /* FALLTHROUGH */
5143 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005144 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5145 if (f < 0)
5146 goto ecreate;
5147 break;
5148 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005149 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5150 if (f < 0)
5151 goto ecreate;
5152 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005153 }
5154
5155 return f;
5156 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005157 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005158 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005159 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005160}
5161
5162/*
Denys Vlasenko64774602016-10-26 15:24:30 +02005163 * Copy a file descriptor to be >= 10. Throws exception on error.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005164 */
5165static int
Denys Vlasenko64774602016-10-26 15:24:30 +02005166savefd(int from)
5167{
5168 int newfd;
5169 int err;
5170
5171 newfd = fcntl(from, F_DUPFD, 10);
5172 err = newfd < 0 ? errno : 0;
5173 if (err != EBADF) {
5174 if (err)
5175 ash_msg_and_raise_error("%d: %m", from);
5176 close(from);
5177 fcntl(newfd, F_SETFD, FD_CLOEXEC);
5178 }
5179
5180 return newfd;
5181}
5182static int
5183dup2_or_raise(int from, int to)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005184{
5185 int newfd;
5186
Denys Vlasenko64774602016-10-26 15:24:30 +02005187 newfd = (from != to) ? dup2(from, to) : to;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005188 if (newfd < 0) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005189 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005190 ash_msg_and_raise_error("%d: %m", from);
5191 }
5192 return newfd;
5193}
5194
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005195/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005196struct two_fd_t {
5197 int orig, copy;
5198};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005199struct redirtab {
5200 struct redirtab *next;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005201 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005202 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005203};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005204#define redirlist (G_var.redirlist)
Denys Vlasenko64774602016-10-26 15:24:30 +02005205enum {
5206 COPYFD_RESTORE = (int)~(INT_MAX),
5207};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005208
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005209static int
5210need_to_remember(struct redirtab *rp, int fd)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005211{
5212 int i;
5213
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005214 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005215 return 0;
5216
5217 for (i = 0; i < rp->pair_count; i++) {
5218 if (rp->two_fd[i].orig == fd) {
5219 /* already remembered */
5220 return 0;
5221 }
5222 }
5223 return 1;
5224}
5225
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005226/* "hidden" fd is a fd used to read scripts, or a copy of such */
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02005227static int
5228is_hidden_fd(struct redirtab *rp, int fd)
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005229{
5230 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005231 struct parsefile *pf;
5232
5233 if (fd == -1)
5234 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005235 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005236 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005237 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005238 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005239 * $ ash # running ash interactively
5240 * $ . ./script.sh
5241 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005242 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005243 * it's still ok to use it: "read" builtin uses it,
5244 * why should we cripple "exec" builtin?
5245 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005246 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005247 return 1;
5248 }
5249 pf = pf->prev;
5250 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005251
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005252 if (!rp)
5253 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005254 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005255 fd |= COPYFD_RESTORE;
5256 for (i = 0; i < rp->pair_count; i++) {
5257 if (rp->two_fd[i].copy == fd) {
5258 return 1;
5259 }
5260 }
5261 return 0;
5262}
5263
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005264/*
5265 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5266 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005267 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005268 */
5269/* flags passed to redirect */
5270#define REDIR_PUSH 01 /* save previous values of file descriptors */
5271#define REDIR_SAVEFD2 03 /* set preverrout */
5272static void
5273redirect(union node *redir, int flags)
5274{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005275 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005276 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005277 int i;
5278 int fd;
5279 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005280 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005281
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005282 if (!redir) {
5283 return;
5284 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005285
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005286 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005287 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005288 INT_OFF;
5289 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005290 union node *tmp = redir;
5291 do {
5292 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005293#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005294 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005295 sv_pos++;
5296#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005297 tmp = tmp->nfile.next;
5298 } while (tmp);
5299 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005300 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005301 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005302 redirlist = sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005303 while (sv_pos > 0) {
5304 sv_pos--;
5305 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5306 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005307 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005308
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005309 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005310 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005311 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005312 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005313 right_fd = redir->ndup.dupfd;
5314 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005315 /* redirect from/to same file descriptor? */
5316 if (right_fd == fd)
5317 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005318 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005319 if (is_hidden_fd(sv, right_fd)) {
5320 errno = EBADF; /* as if it is closed */
5321 ash_msg_and_raise_error("%d: %m", right_fd);
5322 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005323 newfd = -1;
5324 } else {
5325 newfd = openredirect(redir); /* always >= 0 */
5326 if (fd == newfd) {
5327 /* Descriptor wasn't open before redirect.
5328 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005329 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005330 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005331 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005332 continue;
5333 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005334 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005335#if ENABLE_ASH_BASH_COMPAT
5336 redirect_more:
5337#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005338 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005339 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005340 /* Careful to not accidentally "save"
5341 * to the same fd as right side fd in N>&M */
5342 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5343 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005344/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5345 * are closed in popredir() in the child, preventing them from leaking
5346 * into child. (popredir() also cleans up the mess in case of failures)
5347 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005348 if (i == -1) {
5349 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005350 if (i != EBADF) {
5351 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005352 if (newfd >= 0)
5353 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005354 errno = i;
5355 ash_msg_and_raise_error("%d: %m", fd);
5356 /* NOTREACHED */
5357 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005358 /* EBADF: it is not open - good, remember to close it */
5359 remember_to_close:
5360 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005361 } else { /* fd is open, save its copy */
5362 /* "exec fd>&-" should not close fds
5363 * which point to script file(s).
5364 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005365 if (is_hidden_fd(sv, fd))
5366 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005367 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005368 if (fd == 2)
5369 copied_fd2 = i;
5370 sv->two_fd[sv_pos].orig = fd;
5371 sv->two_fd[sv_pos].copy = i;
5372 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005373 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005374 if (newfd < 0) {
5375 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005376 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005377 /* Don't want to trigger debugging */
5378 if (fd != -1)
5379 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005380 } else {
Denys Vlasenko64774602016-10-26 15:24:30 +02005381 dup2_or_raise(redir->ndup.dupfd, fd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005382 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005383 } else if (fd != newfd) { /* move newfd to fd */
Denys Vlasenko64774602016-10-26 15:24:30 +02005384 dup2_or_raise(newfd, fd);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005385#if ENABLE_ASH_BASH_COMPAT
5386 if (!(redir->nfile.type == NTO2 && fd == 2))
5387#endif
5388 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005389 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005390#if ENABLE_ASH_BASH_COMPAT
5391 if (redir->nfile.type == NTO2 && fd == 1) {
5392 /* We already redirected it to fd 1, now copy it to 2 */
5393 newfd = 1;
5394 fd = 2;
5395 goto redirect_more;
5396 }
5397#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005398 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005399
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005400 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005401 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5402 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005403}
5404
5405/*
5406 * Undo the effects of the last redirection.
5407 */
5408static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005409popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005410{
5411 struct redirtab *rp;
5412 int i;
5413
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02005414 if (redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005415 return;
5416 INT_OFF;
5417 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005418 for (i = 0; i < rp->pair_count; i++) {
5419 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005420 int copy = rp->two_fd[i].copy;
5421 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005422 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005423 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005424 continue;
5425 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005426 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005427 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005428 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005429 /*close(fd);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005430 dup2_or_raise(copy, fd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005431 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005432 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005433 }
5434 }
5435 redirlist = rp->next;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005436 free(rp);
5437 INT_ON;
5438}
5439
5440/*
5441 * Undo all redirections. Called on error or interrupt.
5442 */
5443
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005444static int
5445redirectsafe(union node *redir, int flags)
5446{
5447 int err;
5448 volatile int saveint;
5449 struct jmploc *volatile savehandler = exception_handler;
5450 struct jmploc jmploc;
5451
5452 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005453 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5454 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005455 if (!err) {
5456 exception_handler = &jmploc;
5457 redirect(redir, flags);
5458 }
5459 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005460 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005461 longjmp(exception_handler->loc, 1);
5462 RESTORE_INT(saveint);
5463 return err;
5464}
5465
5466
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005467/* ============ Routines to expand arguments to commands
5468 *
5469 * We have to deal with backquotes, shell variables, and file metacharacters.
5470 */
5471
Mike Frysinger98c52642009-04-02 10:02:37 +00005472#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005473static arith_t
5474ash_arith(const char *s)
5475{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005476 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005477 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005478
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005479 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005480 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005481 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005482
5483 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005484 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005485 if (math_state.errmsg)
5486 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005487 INT_ON;
5488
5489 return result;
5490}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005491#endif
5492
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005493/*
5494 * expandarg flags
5495 */
5496#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5497#define EXP_TILDE 0x2 /* do normal tilde expansion */
5498#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5499#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
Denys Vlasenkodb74c6c2016-10-24 21:12:33 +02005500/* ^^^^^^^^^^^^^^ this is meant to support constructs such as "cmd >file*.txt"
5501 * POSIX says for this case:
5502 * Pathname expansion shall not be performed on the word by a
5503 * non-interactive shell; an interactive shell may perform it, but shall
5504 * do so only when the expansion would result in one word.
5505 * Currently, our code complies to the above rule by never globbing
5506 * redirection filenames.
5507 * Bash performs globbing, unless it is non-interactive and in POSIX mode.
5508 * (this means that on a typical Linux distro, bash almost always
5509 * performs globbing, and thus diverges from what we do).
5510 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005511#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005512#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005513#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5514#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005515#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005516/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005517 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005518 */
5519#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5520#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005521#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5522#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005523#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005524
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005525/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005526#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005527/* Do not skip NUL characters. */
5528#define QUOTES_KEEPNUL EXP_TILDE
5529
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005530/*
5531 * Structure specifying which parts of the string should be searched
5532 * for IFS characters.
5533 */
5534struct ifsregion {
5535 struct ifsregion *next; /* next region in list */
5536 int begoff; /* offset of start of region */
5537 int endoff; /* offset of end of region */
5538 int nulonly; /* search for nul bytes only */
5539};
5540
5541struct arglist {
5542 struct strlist *list;
5543 struct strlist **lastp;
5544};
5545
5546/* output of current string */
5547static char *expdest;
5548/* list of back quote expressions */
5549static struct nodelist *argbackq;
5550/* first struct in list of ifs regions */
5551static struct ifsregion ifsfirst;
5552/* last struct in list */
5553static struct ifsregion *ifslastp;
5554/* holds expanded arg list */
5555static struct arglist exparg;
5556
5557/*
5558 * Our own itoa().
5559 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005560#if !ENABLE_SH_MATH_SUPPORT
5561/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5562typedef long arith_t;
5563# define ARITH_FMT "%ld"
5564#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005565static int
5566cvtnum(arith_t num)
5567{
5568 int len;
5569
Denys Vlasenko9c541002015-10-07 15:44:36 +02005570 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5571 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005572 STADJUST(len, expdest);
5573 return len;
5574}
5575
Denys Vlasenko455e4222016-10-27 14:45:13 +02005576/*
5577 * Break the argument string into pieces based upon IFS and add the
5578 * strings to the argument list. The regions of the string to be
5579 * searched for IFS characters have been stored by recordregion.
5580 */
5581static void
5582ifsbreakup(char *string, struct arglist *arglist)
5583{
5584 struct ifsregion *ifsp;
5585 struct strlist *sp;
5586 char *start;
5587 char *p;
5588 char *q;
5589 const char *ifs, *realifs;
5590 int ifsspc;
5591 int nulonly;
5592
5593 start = string;
5594 if (ifslastp != NULL) {
5595 ifsspc = 0;
5596 nulonly = 0;
5597 realifs = ifsset() ? ifsval() : defifs;
5598 ifsp = &ifsfirst;
5599 do {
5600 p = string + ifsp->begoff;
5601 nulonly = ifsp->nulonly;
5602 ifs = nulonly ? nullstr : realifs;
5603 ifsspc = 0;
5604 while (p < string + ifsp->endoff) {
5605 q = p;
5606 if ((unsigned char)*p == CTLESC)
5607 p++;
5608 if (!strchr(ifs, *p)) {
5609 p++;
5610 continue;
5611 }
5612 if (!nulonly)
5613 ifsspc = (strchr(defifs, *p) != NULL);
5614 /* Ignore IFS whitespace at start */
5615 if (q == start && ifsspc) {
5616 p++;
5617 start = p;
5618 continue;
5619 }
5620 *q = '\0';
5621 sp = stzalloc(sizeof(*sp));
5622 sp->text = start;
5623 *arglist->lastp = sp;
5624 arglist->lastp = &sp->next;
5625 p++;
5626 if (!nulonly) {
5627 for (;;) {
5628 if (p >= string + ifsp->endoff) {
5629 break;
5630 }
5631 q = p;
5632 if ((unsigned char)*p == CTLESC)
5633 p++;
5634 if (strchr(ifs, *p) == NULL) {
5635 p = q;
5636 break;
5637 }
5638 if (strchr(defifs, *p) == NULL) {
5639 if (ifsspc) {
5640 p++;
5641 ifsspc = 0;
5642 } else {
5643 p = q;
5644 break;
5645 }
5646 } else
5647 p++;
5648 }
5649 }
5650 start = p;
5651 } /* while */
5652 ifsp = ifsp->next;
5653 } while (ifsp != NULL);
5654 if (nulonly)
5655 goto add;
5656 }
5657
5658 if (!*start)
5659 return;
5660
5661 add:
5662 sp = stzalloc(sizeof(*sp));
5663 sp->text = start;
5664 *arglist->lastp = sp;
5665 arglist->lastp = &sp->next;
5666}
5667
5668static void
5669ifsfree(void)
5670{
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005671 struct ifsregion *p = ifsfirst.next;
5672
5673 if (!p)
5674 goto out;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005675
5676 INT_OFF;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005677 do {
5678 struct ifsregion *ifsp;
5679 ifsp = p->next;
5680 free(p);
5681 p = ifsp;
5682 } while (p);
Denys Vlasenko455e4222016-10-27 14:45:13 +02005683 ifsfirst.next = NULL;
5684 INT_ON;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02005685 out:
5686 ifslastp = NULL;
Denys Vlasenko455e4222016-10-27 14:45:13 +02005687}
5688
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005689static size_t
5690esclen(const char *start, const char *p)
5691{
5692 size_t esc = 0;
5693
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005694 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005695 esc++;
5696 }
5697 return esc;
5698}
5699
5700/*
5701 * Remove any CTLESC characters from a string.
5702 */
5703static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005704rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005705{
Ron Yorston417622c2015-05-18 09:59:14 +02005706 static const char qchars[] ALIGN1 = {
5707 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005708
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005709 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005710 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005711 unsigned protect_against_glob;
5712 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005713 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005714
Ron Yorston417622c2015-05-18 09:59:14 +02005715 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005716 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005717 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005718
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005719 q = p;
5720 r = str;
5721 if (flag & RMESCAPE_ALLOC) {
5722 size_t len = p - str;
5723 size_t fulllen = len + strlen(p) + 1;
5724
5725 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005726 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005727 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005728 /* p and str may be invalidated by makestrspace */
5729 str = (char *)stackblock() + strloc;
5730 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005731 } else if (flag & RMESCAPE_HEAP) {
5732 r = ckmalloc(fulllen);
5733 } else {
5734 r = stalloc(fulllen);
5735 }
5736 q = r;
5737 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005738 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005739 }
5740 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005741
Ron Yorston549deab2015-05-18 09:57:51 +02005742 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005743 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005744 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005745 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005746 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005747// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005748 inquotes = ~inquotes;
5749 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005750 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005751 continue;
5752 }
Ron Yorston549deab2015-05-18 09:57:51 +02005753 if ((unsigned char)*p == CTLESC) {
5754 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005755#if DEBUG
5756 if (*p == '\0')
5757 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5758#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005759 if (protect_against_glob) {
5760 *q++ = '\\';
5761 }
5762 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005763 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005764 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005765 goto copy;
5766 }
Ron Yorston417622c2015-05-18 09:59:14 +02005767#if ENABLE_ASH_BASH_COMPAT
5768 else if (*p == '/' && slash) {
5769 /* stop handling globbing and mark location of slash */
5770 globbing = slash = 0;
5771 *p = CTLESC;
5772 }
5773#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005774 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005775 copy:
5776 *q++ = *p++;
5777 }
5778 *q = '\0';
5779 if (flag & RMESCAPE_GROW) {
5780 expdest = r;
5781 STADJUST(q - r + 1, expdest);
5782 }
5783 return r;
5784}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005785#define pmatch(a, b) !fnmatch((a), (b), 0)
5786
5787/*
5788 * Prepare a pattern for a expmeta (internal glob(3)) call.
5789 *
5790 * Returns an stalloced string.
5791 */
5792static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005793preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005794{
Ron Yorston549deab2015-05-18 09:57:51 +02005795 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005796}
5797
5798/*
5799 * Put a string on the stack.
5800 */
5801static void
5802memtodest(const char *p, size_t len, int syntax, int quotes)
5803{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005804 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005805
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005806 if (!len)
5807 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005808
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005809 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5810
5811 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005812 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005813 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005814 int n = SIT(c, syntax);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005815 if ((quotes & QUOTES_ESC)
5816 && ((n == CCTL)
5817 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5818 && n == CBACK)
5819 )
5820 ) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005821 USTPUTC(CTLESC, q);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005822 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005823 } else if (!(quotes & QUOTES_KEEPNUL))
5824 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005825 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005826 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005827
5828 expdest = q;
5829}
5830
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005831static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005832strtodest(const char *p, int syntax, int quotes)
5833{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005834 size_t len = strlen(p);
5835 memtodest(p, len, syntax, quotes);
5836 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005837}
5838
5839/*
5840 * Record the fact that we have to scan this region of the
5841 * string for IFS characters.
5842 */
5843static void
5844recordregion(int start, int end, int nulonly)
5845{
5846 struct ifsregion *ifsp;
5847
5848 if (ifslastp == NULL) {
5849 ifsp = &ifsfirst;
5850 } else {
5851 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005852 ifsp = ckzalloc(sizeof(*ifsp));
5853 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005854 ifslastp->next = ifsp;
5855 INT_ON;
5856 }
5857 ifslastp = ifsp;
5858 ifslastp->begoff = start;
5859 ifslastp->endoff = end;
5860 ifslastp->nulonly = nulonly;
5861}
5862
5863static void
5864removerecordregions(int endoff)
5865{
5866 if (ifslastp == NULL)
5867 return;
5868
5869 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005870 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005871 struct ifsregion *ifsp;
5872 INT_OFF;
5873 ifsp = ifsfirst.next->next;
5874 free(ifsfirst.next);
5875 ifsfirst.next = ifsp;
5876 INT_ON;
5877 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005878 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005879 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005880 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005881 ifslastp = &ifsfirst;
5882 ifsfirst.endoff = endoff;
5883 }
5884 return;
5885 }
5886
5887 ifslastp = &ifsfirst;
5888 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005889 ifslastp = ifslastp->next;
5890 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005891 struct ifsregion *ifsp;
5892 INT_OFF;
5893 ifsp = ifslastp->next->next;
5894 free(ifslastp->next);
5895 ifslastp->next = ifsp;
5896 INT_ON;
5897 }
5898 if (ifslastp->endoff > endoff)
5899 ifslastp->endoff = endoff;
5900}
5901
5902static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005903exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005904{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005905 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005906 char *name;
5907 struct passwd *pw;
5908 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005909 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005910
5911 name = p + 1;
5912
5913 while ((c = *++p) != '\0') {
5914 switch (c) {
5915 case CTLESC:
5916 return startp;
5917 case CTLQUOTEMARK:
5918 return startp;
5919 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005920 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005921 goto done;
5922 break;
5923 case '/':
5924 case CTLENDVAR:
5925 goto done;
5926 }
5927 }
5928 done:
5929 *p = '\0';
5930 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005931 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005932 } else {
5933 pw = getpwnam(name);
5934 if (pw == NULL)
5935 goto lose;
5936 home = pw->pw_dir;
5937 }
5938 if (!home || !*home)
5939 goto lose;
5940 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005941 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005942 return p;
5943 lose:
5944 *p = c;
5945 return startp;
5946}
5947
5948/*
5949 * Execute a command inside back quotes. If it's a builtin command, we
5950 * want to save its output in a block obtained from malloc. Otherwise
5951 * we fork off a subprocess and get the output of the command via a pipe.
5952 * Should be called with interrupts off.
5953 */
5954struct backcmd { /* result of evalbackcmd */
5955 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005956 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005957 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005958 struct job *jp; /* job structure for command */
5959};
5960
5961/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005962#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02005963static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005964
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005965static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966evalbackcmd(union node *n, struct backcmd *result)
5967{
Denys Vlasenko579ad102016-10-25 21:10:20 +02005968 int pip[2];
5969 struct job *jp;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005970
5971 result->fd = -1;
5972 result->buf = NULL;
5973 result->nleft = 0;
5974 result->jp = NULL;
Denys Vlasenko579ad102016-10-25 21:10:20 +02005975 if (n == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005976 goto out;
Denys Vlasenko579ad102016-10-25 21:10:20 +02005977 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005978
Denys Vlasenko579ad102016-10-25 21:10:20 +02005979 if (pipe(pip) < 0)
5980 ash_msg_and_raise_error("pipe call failed");
5981 jp = makejob(/*n,*/ 1);
5982 if (forkshell(jp, n, FORK_NOJOB) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02005983 /* child */
Denys Vlasenko579ad102016-10-25 21:10:20 +02005984 FORCE_INT_ON;
5985 close(pip[0]);
5986 if (pip[1] != 1) {
5987 /*close(1);*/
Denys Vlasenko64774602016-10-26 15:24:30 +02005988 dup2_or_raise(pip[1], 1);
Denys Vlasenko579ad102016-10-25 21:10:20 +02005989 close(pip[1]);
5990 }
Denys Vlasenko960ca382016-10-25 18:12:15 +02005991/* TODO: eflag clearing makes the following not abort:
5992 * ash -c 'set -e; z=$(false;echo foo); echo $z'
5993 * which is what bash does (unless it is in POSIX mode).
5994 * dash deleted "eflag = 0" line in the commit
5995 * Date: Mon, 28 Jun 2010 17:11:58 +1000
5996 * [EVAL] Don't clear eflag in evalbackcmd
5997 * For now, preserve bash-like behavior, it seems to be somewhat more useful:
5998 */
Denys Vlasenko579ad102016-10-25 21:10:20 +02005999 eflag = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02006000 ifsfree();
Denys Vlasenko579ad102016-10-25 21:10:20 +02006001 evaltree(n, EV_EXIT); /* actually evaltreenr... */
6002 /* NOTREACHED */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006003 }
Denys Vlasenko70392332016-10-27 02:31:55 +02006004 /* parent */
Denys Vlasenko579ad102016-10-25 21:10:20 +02006005 close(pip[1]);
6006 result->fd = pip[0];
6007 result->jp = jp;
6008
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006009 out:
6010 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
6011 result->fd, result->buf, result->nleft, result->jp));
6012}
6013
6014/*
6015 * Expand stuff in backwards quotes.
6016 */
6017static void
Ron Yorston549deab2015-05-18 09:57:51 +02006018expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006019{
6020 struct backcmd in;
6021 int i;
6022 char buf[128];
6023 char *p;
6024 char *dest;
6025 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02006026 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006027 struct stackmark smark;
6028
6029 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02006030 startloc = expdest - (char *)stackblock();
6031 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006032 evalbackcmd(cmd, &in);
6033 popstackmark(&smark);
6034
6035 p = in.buf;
6036 i = in.nleft;
6037 if (i == 0)
6038 goto read;
6039 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02006040 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006041 read:
6042 if (in.fd < 0)
6043 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01006044 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006045 TRACE(("expbackq: read returns %d\n", i));
6046 if (i <= 0)
6047 break;
6048 p = buf;
6049 }
6050
Denis Vlasenko60818682007-09-28 22:07:23 +00006051 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006052 if (in.fd >= 0) {
6053 close(in.fd);
6054 back_exitstatus = waitforjob(in.jp);
6055 }
6056 INT_ON;
6057
6058 /* Eat all trailing newlines */
6059 dest = expdest;
6060 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
6061 STUNPUTC(dest);
6062 expdest = dest;
6063
Ron Yorston549deab2015-05-18 09:57:51 +02006064 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006065 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006066 TRACE(("evalbackq: size:%d:'%.*s'\n",
6067 (int)((dest - (char *)stackblock()) - startloc),
6068 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069 stackblock() + startloc));
6070}
6071
Mike Frysinger98c52642009-04-02 10:02:37 +00006072#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006073/*
6074 * Expand arithmetic expression. Backup to start of expression,
6075 * evaluate, place result in (backed up) result, adjust string position.
6076 */
6077static void
Ron Yorston549deab2015-05-18 09:57:51 +02006078expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006079{
6080 char *p, *start;
6081 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006082 int len;
6083
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006084 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006085
6086 /*
6087 * This routine is slightly over-complicated for
6088 * efficiency. Next we scan backwards looking for the
6089 * start of arithmetic.
6090 */
6091 start = stackblock();
6092 p = expdest - 1;
6093 *p = '\0';
6094 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006095 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006096 int esc;
6097
Denys Vlasenkocd716832009-11-28 22:14:02 +01006098 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006099 p--;
6100#if DEBUG
6101 if (p < start) {
6102 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6103 }
6104#endif
6105 }
6106
6107 esc = esclen(start, p);
6108 if (!(esc % 2)) {
6109 break;
6110 }
6111
6112 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006113 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006114
6115 begoff = p - start;
6116
6117 removerecordregions(begoff);
6118
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006119 expdest = p;
6120
Ron Yorston549deab2015-05-18 09:57:51 +02006121 if (flag & QUOTES_ESC)
6122 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006123
Ron Yorston549deab2015-05-18 09:57:51 +02006124 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006125
Ron Yorston549deab2015-05-18 09:57:51 +02006126 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006127 recordregion(begoff, begoff + len, 0);
6128}
6129#endif
6130
6131/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006132static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006133
6134/*
6135 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6136 * characters to allow for further processing. Otherwise treat
6137 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006138 *
6139 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6140 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6141 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006142 */
6143static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006144argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006145{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006146 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006147 '=',
6148 ':',
6149 CTLQUOTEMARK,
6150 CTLENDVAR,
6151 CTLESC,
6152 CTLVAR,
6153 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006154#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006155 CTLENDARI,
6156#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006157 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006158 };
6159 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006160 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006161 int inquotes;
6162 size_t length;
6163 int startloc;
6164
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006165 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006166 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006167 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006168 reject++;
6169 }
6170 inquotes = 0;
6171 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006172 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006173 char *q;
6174
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006175 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006176 tilde:
6177 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006178 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006179 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006180 }
6181 start:
6182 startloc = expdest - (char *)stackblock();
6183 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006184 unsigned char c;
6185
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006186 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006187 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006188 if (c) {
6189 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006190 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006191 ) {
6192 /* c == '=' || c == ':' || c == CTLENDARI */
6193 length++;
6194 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006195 }
6196 if (length > 0) {
6197 int newloc;
6198 expdest = stack_nputstr(p, length, expdest);
6199 newloc = expdest - (char *)stackblock();
6200 if (breakall && !inquotes && newloc > startloc) {
6201 recordregion(startloc, newloc, 0);
6202 }
6203 startloc = newloc;
6204 }
6205 p += length + 1;
6206 length = 0;
6207
6208 switch (c) {
6209 case '\0':
6210 goto breakloop;
6211 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006212 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006213 p--;
6214 continue;
6215 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006216 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006217 reject++;
6218 /* fall through */
6219 case ':':
6220 /*
6221 * sort of a hack - expand tildes in variable
6222 * assignments (after the first '=' and after ':'s).
6223 */
6224 if (*--p == '~') {
6225 goto tilde;
6226 }
6227 continue;
6228 }
6229
6230 switch (c) {
6231 case CTLENDVAR: /* ??? */
6232 goto breakloop;
6233 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006234 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006235 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006236 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6237 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006238 goto start;
6239 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006240 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006241 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006242 p--;
6243 length++;
6244 startloc++;
6245 }
6246 break;
6247 case CTLESC:
6248 startloc++;
6249 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006250
6251 /*
6252 * Quoted parameter expansion pattern: remove quote
6253 * unless inside inner quotes or we have a literal
6254 * backslash.
6255 */
6256 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6257 EXP_QPAT && *p != '\\')
6258 break;
6259
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006260 goto addquote;
6261 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006262 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006263 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006264 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265 goto start;
6266 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006267 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006268 argbackq = argbackq->next;
6269 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006270#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006271 case CTLENDARI:
6272 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006273 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006274 goto start;
6275#endif
6276 }
6277 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006278 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006279}
6280
6281static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006282scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6283 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006284{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006285 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006286 char c;
6287
6288 loc = startp;
6289 loc2 = rmesc;
6290 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006291 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006293
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006294 c = *loc2;
6295 if (zero) {
6296 *loc2 = '\0';
6297 s = rmesc;
6298 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006299 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006300
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006301 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006302 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006303 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006304 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006305 loc++;
6306 loc++;
6307 loc2++;
6308 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006309 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006310}
6311
6312static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006313scanright(char *startp, char *rmesc, char *rmescend,
6314 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006315{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006316#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6317 int try2optimize = match_at_start;
6318#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006319 int esc = 0;
6320 char *loc;
6321 char *loc2;
6322
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006323 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6324 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6325 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6326 * Logic:
6327 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6328 * and on each iteration they go back two/one char until they reach the beginning.
6329 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6330 */
6331 /* TODO: document in what other circumstances we are called. */
6332
6333 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334 int match;
6335 char c = *loc2;
6336 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006337 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006338 *loc2 = '\0';
6339 s = rmesc;
6340 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006341 match = pmatch(pattern, s);
6342 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006343 *loc2 = c;
6344 if (match)
6345 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006346#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6347 if (try2optimize) {
6348 /* Maybe we can optimize this:
6349 * if pattern ends with unescaped *, we can avoid checking
6350 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6351 * it wont match truncated "raw_value_of_" strings too.
6352 */
6353 unsigned plen = strlen(pattern);
6354 /* Does it end with "*"? */
6355 if (plen != 0 && pattern[--plen] == '*') {
6356 /* "xxxx*" is not escaped */
6357 /* "xxx\*" is escaped */
6358 /* "xx\\*" is not escaped */
6359 /* "x\\\*" is escaped */
6360 int slashes = 0;
6361 while (plen != 0 && pattern[--plen] == '\\')
6362 slashes++;
6363 if (!(slashes & 1))
6364 break; /* ends with unescaped "*" */
6365 }
6366 try2optimize = 0;
6367 }
6368#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006369 loc--;
6370 if (quotes) {
6371 if (--esc < 0) {
6372 esc = esclen(startp, loc);
6373 }
6374 if (esc % 2) {
6375 esc--;
6376 loc--;
6377 }
6378 }
6379 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006380 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006381}
6382
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006383static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006384static void
6385varunset(const char *end, const char *var, const char *umsg, int varflags)
6386{
6387 const char *msg;
6388 const char *tail;
6389
6390 tail = nullstr;
6391 msg = "parameter not set";
6392 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006393 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006394 if (varflags & VSNUL)
6395 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006396 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006397 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006398 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006399 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006400 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006401}
6402
6403static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006404subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006405 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006406{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006407 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006408 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006409 char *startp;
6410 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006411 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006412 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006413 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006414 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006415 int amount, resetloc;
6416 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006417 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006418 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006419
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006420 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6421 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006422
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006423 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006424 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6425 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006426 STPUTC('\0', expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006427 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006428 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429
6430 switch (subtype) {
6431 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006432 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006433 amount = startp - expdest;
6434 STADJUST(amount, expdest);
6435 return startp;
6436
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006437 case VSQUESTION:
6438 varunset(p, varname, startp, varflags);
6439 /* NOTREACHED */
6440
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006441#if ENABLE_ASH_BASH_COMPAT
6442 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006443//TODO: support more general format ${v:EXPR:EXPR},
6444// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006445 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006446 /* Read POS in ${var:POS:LEN} */
6447 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006448 len = str - startp - 1;
6449
6450 /* *loc != '\0', guaranteed by parser */
6451 if (quotes) {
6452 char *ptr;
6453
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006454 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006455 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006456 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006457 len--;
6458 ptr++;
6459 }
6460 }
6461 }
6462 orig_len = len;
6463
6464 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006465 /* ${var::LEN} */
6466 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006467 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006468 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006469 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006470 while (*loc && *loc != ':') {
6471 /* TODO?
6472 * bash complains on: var=qwe; echo ${var:1a:123}
6473 if (!isdigit(*loc))
6474 ash_msg_and_raise_error(msg_illnum, str);
6475 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006476 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006477 }
6478 if (*loc++ == ':') {
6479 len = number(loc);
6480 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006481 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006482 if (pos < 0) {
6483 /* ${VAR:$((-n)):l} starts n chars from the end */
6484 pos = orig_len + pos;
6485 }
6486 if ((unsigned)pos >= orig_len) {
6487 /* apart from obvious ${VAR:999999:l},
6488 * covers ${VAR:$((-9999999)):l} - result is ""
6489 * (bash-compat)
6490 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006491 pos = 0;
6492 len = 0;
6493 }
6494 if (len > (orig_len - pos))
6495 len = orig_len - pos;
6496
6497 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006498 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006499 str++;
6500 }
6501 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006502 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006503 *loc++ = *str++;
6504 *loc++ = *str++;
6505 }
6506 *loc = '\0';
6507 amount = loc - expdest;
6508 STADJUST(amount, expdest);
6509 return loc;
6510#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006511 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006512
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006513 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006514
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006515 /* We'll comeback here if we grow the stack while handling
6516 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6517 * stack will need rebasing, and we'll need to remove our work
6518 * areas each time
6519 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006520 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006521
6522 amount = expdest - ((char *)stackblock() + resetloc);
6523 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006524 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006525
6526 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006527 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006528 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006529 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006530 if (rmesc != startp) {
6531 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006532 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006533 }
6534 }
6535 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006536 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006537 /*
6538 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6539 * The result is a_\_z_c (not a\_\_z_c)!
6540 *
6541 * The search pattern and replace string treat backslashes differently!
6542 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6543 * and string. It's only used on the first call.
6544 */
6545 preglob(str, IF_ASH_BASH_COMPAT(
6546 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6547 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006548
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006549#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006550 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006551 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006552 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006553
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006554 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006555 repl = strchr(str, CTLESC);
6556 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006557 *repl++ = '\0';
6558 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006559 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006560 }
Ron Yorston417622c2015-05-18 09:59:14 +02006561 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006562
6563 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006564 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006565 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006566
6567 len = 0;
6568 idx = startp;
6569 end = str - 1;
6570 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006571 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006572 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006573 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006574 if (!loc) {
6575 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006576 char *restart_detect = stackblock();
6577 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006578 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006579 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006580 idx++;
6581 len++;
6582 STPUTC(*idx, expdest);
6583 }
6584 if (stackblock() != restart_detect)
6585 goto restart;
6586 idx++;
6587 len++;
6588 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006589 /* continue; - prone to quadratic behavior, smarter code: */
6590 if (idx >= end)
6591 break;
6592 if (str[0] == '*') {
6593 /* Pattern is "*foo". If "*foo" does not match "long_string",
6594 * it would never match "ong_string" etc, no point in trying.
6595 */
6596 goto skip_matching;
6597 }
6598 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006599 }
6600
6601 if (subtype == VSREPLACEALL) {
6602 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006603 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006604 idx++;
6605 idx++;
6606 rmesc++;
6607 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006608 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006609 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006610 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006611
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006612 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006613 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006614 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006615 if (quotes && *loc == '\\') {
6616 STPUTC(CTLESC, expdest);
6617 len++;
6618 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006619 STPUTC(*loc, expdest);
6620 if (stackblock() != restart_detect)
6621 goto restart;
6622 len++;
6623 }
6624
6625 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006626 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006627 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006628 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006629 STPUTC(*idx, expdest);
6630 if (stackblock() != restart_detect)
6631 goto restart;
6632 len++;
6633 idx++;
6634 }
6635 break;
6636 }
6637 }
6638
6639 /* We've put the replaced text into a buffer at workloc, now
6640 * move it to the right place and adjust the stack.
6641 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006642 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006643 startp = (char *)stackblock() + startloc;
6644 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006645 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006646 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006647 STADJUST(-amount, expdest);
6648 return startp;
6649 }
6650#endif /* ENABLE_ASH_BASH_COMPAT */
6651
6652 subtype -= VSTRIMRIGHT;
6653#if DEBUG
6654 if (subtype < 0 || subtype > 7)
6655 abort();
6656#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006657 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006658 zero = subtype >> 1;
6659 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6660 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6661
6662 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6663 if (loc) {
6664 if (zero) {
6665 memmove(startp, loc, str - loc);
6666 loc = startp + (str - loc) - 1;
6667 }
6668 *loc = '\0';
6669 amount = loc - expdest;
6670 STADJUST(amount, expdest);
6671 }
6672 return loc;
6673}
6674
6675/*
6676 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006677 * name parameter (examples):
6678 * ash -c 'echo $1' name:'1='
6679 * ash -c 'echo $qwe' name:'qwe='
6680 * ash -c 'echo $$' name:'$='
6681 * ash -c 'echo ${$}' name:'$='
6682 * ash -c 'echo ${$##q}' name:'$=q'
6683 * ash -c 'echo ${#$}' name:'$='
6684 * note: examples with bad shell syntax:
6685 * ash -c 'echo ${#$1}' name:'$=1'
6686 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006687 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006688static NOINLINE ssize_t
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006689varvalue(char *name, int varflags, int flags, struct strlist *var_str_list, int *quotedp)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006690{
Mike Frysinger98c52642009-04-02 10:02:37 +00006691 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006692 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006693 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006694 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006695 int sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006696 int quoted = *quotedp;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006697 int subtype = varflags & VSTYPE;
6698 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6699 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006700 int syntax;
6701
6702 sep = (flags & EXP_FULL) << CHAR_BIT;
6703 syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006704
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006705 switch (*name) {
6706 case '$':
6707 num = rootpid;
6708 goto numvar;
6709 case '?':
6710 num = exitstatus;
6711 goto numvar;
6712 case '#':
6713 num = shellparam.nparam;
6714 goto numvar;
6715 case '!':
6716 num = backgndpid;
6717 if (num == 0)
6718 return -1;
6719 numvar:
6720 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006721 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006722 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006723 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006724 for (i = NOPTS - 1; i >= 0; i--) {
6725 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006726 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006727 len++;
6728 }
6729 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006730 check_1char_name:
6731#if 0
6732 /* handles cases similar to ${#$1} */
6733 if (name[2] != '\0')
6734 raise_error_syntax("bad substitution");
6735#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006736 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006737 case '@':
6738 if (quoted && sep)
6739 goto param;
6740 /* fall through */
6741 case '*': {
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006742 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006743 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006744
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006745 if (quoted)
6746 sep = 0;
6747 sep |= ifsset() ? ifsval()[0] : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006748 param:
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006749 sepc = sep;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006750 *quotedp = !sepc;
6751 ap = shellparam.p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006752 if (!ap)
6753 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006754 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006755 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006756
6757 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006758 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006759 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006760 }
6761 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006762 break;
Denys Vlasenko0aaaa502016-10-02 02:46:56 +02006763 } /* case '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006764 case '0':
6765 case '1':
6766 case '2':
6767 case '3':
6768 case '4':
6769 case '5':
6770 case '6':
6771 case '7':
6772 case '8':
6773 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006774 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006775 if (num < 0 || num > shellparam.nparam)
6776 return -1;
6777 p = num ? shellparam.p[num - 1] : arg0;
6778 goto value;
6779 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006780 /* NB: name has form "VAR=..." */
6781
6782 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6783 * which should be considered before we check variables. */
6784 if (var_str_list) {
6785 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6786 p = NULL;
6787 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006788 char *str, *eq;
6789 str = var_str_list->text;
6790 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006791 if (!eq) /* stop at first non-assignment */
6792 break;
6793 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006794 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006795 && strncmp(str, name, name_len) == 0
6796 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006797 p = eq;
6798 /* goto value; - WRONG! */
6799 /* think "A=1 A=2 B=$A" */
6800 }
6801 var_str_list = var_str_list->next;
6802 } while (var_str_list);
6803 if (p)
6804 goto value;
6805 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006806 p = lookupvar(name);
6807 value:
6808 if (!p)
6809 return -1;
6810
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006811 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006812#if ENABLE_UNICODE_SUPPORT
6813 if (subtype == VSLENGTH && len > 0) {
6814 reinit_unicode_for_ash();
6815 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006816 STADJUST(-len, expdest);
6817 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006818 len = unicode_strlen(p);
6819 }
6820 }
6821#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006822 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006823 }
6824
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006825 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006826 STADJUST(-len, expdest);
6827 return len;
6828}
6829
6830/*
6831 * Expand a variable, and return a pointer to the next character in the
6832 * input string.
6833 */
6834static char *
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006835evalvar(char *p, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006836{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006837 char varflags;
6838 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006839 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006840 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006841 char *var;
6842 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006843 int startloc;
6844 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006845
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006846 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006847 subtype = varflags & VSTYPE;
Denys Vlasenko88e15702016-10-26 01:55:56 +02006848
6849 if (!subtype)
6850 raise_error_syntax("bad substitution");
6851
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006852 quoted = flag & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006853 var = p;
6854 easy = (!quoted || (*var == '@' && shellparam.nparam));
6855 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006856 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006857
6858 again:
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006859 varlen = varvalue(var, varflags, flag, var_str_list, &quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006860 if (varflags & VSNUL)
6861 varlen--;
6862
6863 if (subtype == VSPLUS) {
6864 varlen = -1 - varlen;
6865 goto vsplus;
6866 }
6867
6868 if (subtype == VSMINUS) {
6869 vsplus:
6870 if (varlen < 0) {
6871 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006872 p,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006873 flag | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006874 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006875 );
6876 goto end;
6877 }
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006878 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006879 }
6880
6881 if (subtype == VSASSIGN || subtype == VSQUESTION) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006882 if (varlen >= 0)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006883 goto record;
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006884
6885 subevalvar(p, var, 0, subtype, startloc, varflags,
6886 flag & ~QUOTES_ESC, var_str_list);
6887 varflags &= ~VSNUL;
6888 /*
6889 * Remove any recorded regions beyond
6890 * start of variable
6891 */
6892 removerecordregions(startloc);
6893 goto again;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006894 }
6895
6896 if (varlen < 0 && uflag)
6897 varunset(p, var, 0, 0);
6898
6899 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006900 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006901 goto record;
6902 }
6903
6904 if (subtype == VSNORMAL) {
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006905 record:
6906 if (!easy)
6907 goto end;
Denys Vlasenko0dd8e452016-10-01 21:02:06 +02006908 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006909 goto end;
6910 }
6911
6912#if DEBUG
6913 switch (subtype) {
6914 case VSTRIMLEFT:
6915 case VSTRIMLEFTMAX:
6916 case VSTRIMRIGHT:
6917 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006918#if ENABLE_ASH_BASH_COMPAT
6919 case VSSUBSTR:
6920 case VSREPLACE:
6921 case VSREPLACEALL:
6922#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006923 break;
6924 default:
6925 abort();
6926 }
6927#endif
6928
6929 if (varlen >= 0) {
6930 /*
6931 * Terminate the string and start recording the pattern
6932 * right after it
6933 */
6934 STPUTC('\0', expdest);
6935 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006936 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006937 startloc, varflags, flag, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006938 int amount = expdest - (
6939 (char *)stackblock() + patloc - 1
6940 );
6941 STADJUST(-amount, expdest);
6942 }
6943 /* Remove any recorded regions beyond start of variable */
6944 removerecordregions(startloc);
Denys Vlasenko88ac97d2016-10-01 20:55:02 +02006945 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006946 }
6947
6948 end:
6949 if (subtype != VSNORMAL) { /* skip to end of alternative */
6950 int nesting = 1;
6951 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006952 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006953 if (c == CTLESC)
6954 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006955 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006956 if (varlen >= 0)
6957 argbackq = argbackq->next;
6958 } else if (c == CTLVAR) {
6959 if ((*p++ & VSTYPE) != VSNORMAL)
6960 nesting++;
6961 } else if (c == CTLENDVAR) {
6962 if (--nesting == 0)
6963 break;
6964 }
6965 }
6966 }
6967 return p;
6968}
6969
6970/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006971 * Add a file name to the list.
6972 */
6973static void
6974addfname(const char *name)
6975{
6976 struct strlist *sp;
6977
Denis Vlasenko597906c2008-02-20 16:38:54 +00006978 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02006979 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006980 *exparg.lastp = sp;
6981 exparg.lastp = &sp->next;
6982}
6983
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006984/* If we want to use glob() from libc... */
Denys Vlasenko514b51d2016-10-01 14:33:08 +02006985#if !ENABLE_ASH_INTERNAL_GLOB
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006986
6987/* Add the result of glob() to the list */
6988static void
6989addglob(const glob_t *pglob)
6990{
6991 char **p = pglob->gl_pathv;
6992
6993 do {
6994 addfname(*p);
6995 } while (*++p);
6996}
6997static void
6998expandmeta(struct strlist *str /*, int flag*/)
6999{
7000 /* TODO - EXP_REDIR */
7001
7002 while (str) {
7003 char *p;
7004 glob_t pglob;
7005 int i;
7006
7007 if (fflag)
7008 goto nometa;
7009 INT_OFF;
7010 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007011// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7012// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7013//
7014// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7015// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7016// Which means you need to unescape the string, right? Not so fast:
7017// if there _is_ a file named "file\?" (with backslash), it is returned
7018// as "file\?" too (whichever pattern you used to find it, say, "file*").
7019// You DONT KNOW by looking at the result whether you need to unescape it.
7020//
7021// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7022// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7023// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7024// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7025// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7026// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7027 i = glob(p, 0, NULL, &pglob);
7028 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007029 if (p != str->text)
7030 free(p);
7031 switch (i) {
7032 case 0:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007033#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007034 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7035 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7036 goto nometa2;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007037#endif
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007038 addglob(&pglob);
7039 globfree(&pglob);
7040 INT_ON;
7041 break;
7042 case GLOB_NOMATCH:
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007043 //nometa2:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007044 globfree(&pglob);
7045 INT_ON;
Denys Vlasenko8e2c9cc2016-10-02 15:17:15 +02007046 nometa:
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007047 *exparg.lastp = str;
7048 rmescapes(str->text, 0);
7049 exparg.lastp = &str->next;
7050 break;
7051 default: /* GLOB_NOSPACE */
7052 globfree(&pglob);
7053 INT_ON;
7054 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7055 }
7056 str = str->next;
7057 }
7058}
7059
7060#else
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007061/* ENABLE_ASH_INTERNAL_GLOB: Homegrown globbing code. (dash also has both, uses homegrown one.) */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007062
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007063/*
7064 * Do metacharacter (i.e. *, ?, [...]) expansion.
7065 */
7066static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007067expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007068{
7069 char *p;
7070 const char *cp;
7071 char *start;
7072 char *endname;
7073 int metaflag;
7074 struct stat statb;
7075 DIR *dirp;
7076 struct dirent *dp;
7077 int atend;
7078 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007079 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007080
7081 metaflag = 0;
7082 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007083 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007084 if (*p == '*' || *p == '?')
7085 metaflag = 1;
7086 else if (*p == '[') {
7087 char *q = p + 1;
7088 if (*q == '!')
7089 q++;
7090 for (;;) {
7091 if (*q == '\\')
7092 q++;
7093 if (*q == '/' || *q == '\0')
7094 break;
7095 if (*++q == ']') {
7096 metaflag = 1;
7097 break;
7098 }
7099 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007100 } else {
7101 if (*p == '\\')
7102 esc++;
7103 if (p[esc] == '/') {
7104 if (metaflag)
7105 break;
7106 start = p + esc + 1;
7107 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007108 }
7109 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007110 if (metaflag == 0) { /* we've reached the end of the file name */
7111 if (enddir != expdir)
7112 metaflag++;
7113 p = name;
7114 do {
7115 if (*p == '\\')
7116 p++;
7117 *enddir++ = *p;
7118 } while (*p++);
7119 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7120 addfname(expdir);
7121 return;
7122 }
7123 endname = p;
7124 if (name < start) {
7125 p = name;
7126 do {
7127 if (*p == '\\')
7128 p++;
7129 *enddir++ = *p++;
7130 } while (p < start);
7131 }
7132 if (enddir == expdir) {
7133 cp = ".";
7134 } else if (enddir == expdir + 1 && *expdir == '/') {
7135 cp = "/";
7136 } else {
7137 cp = expdir;
7138 enddir[-1] = '\0';
7139 }
7140 dirp = opendir(cp);
7141 if (dirp == NULL)
7142 return;
7143 if (enddir != expdir)
7144 enddir[-1] = '/';
7145 if (*endname == 0) {
7146 atend = 1;
7147 } else {
7148 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007149 *endname = '\0';
7150 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007151 }
7152 matchdot = 0;
7153 p = start;
7154 if (*p == '\\')
7155 p++;
7156 if (*p == '.')
7157 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007158 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007159 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007160 continue;
7161 if (pmatch(start, dp->d_name)) {
7162 if (atend) {
7163 strcpy(enddir, dp->d_name);
7164 addfname(expdir);
7165 } else {
7166 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7167 continue;
7168 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007169 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007170 }
7171 }
7172 }
7173 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007174 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007175 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007176}
7177
7178static struct strlist *
7179msort(struct strlist *list, int len)
7180{
7181 struct strlist *p, *q = NULL;
7182 struct strlist **lpp;
7183 int half;
7184 int n;
7185
7186 if (len <= 1)
7187 return list;
7188 half = len >> 1;
7189 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007190 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007191 q = p;
7192 p = p->next;
7193 }
7194 q->next = NULL; /* terminate first half of list */
7195 q = msort(list, half); /* sort first half of list */
7196 p = msort(p, len - half); /* sort second half */
7197 lpp = &list;
7198 for (;;) {
7199#if ENABLE_LOCALE_SUPPORT
7200 if (strcoll(p->text, q->text) < 0)
7201#else
7202 if (strcmp(p->text, q->text) < 0)
7203#endif
7204 {
7205 *lpp = p;
7206 lpp = &p->next;
7207 p = *lpp;
7208 if (p == NULL) {
7209 *lpp = q;
7210 break;
7211 }
7212 } else {
7213 *lpp = q;
7214 lpp = &q->next;
7215 q = *lpp;
7216 if (q == NULL) {
7217 *lpp = p;
7218 break;
7219 }
7220 }
7221 }
7222 return list;
7223}
7224
7225/*
7226 * Sort the results of file name expansion. It calculates the number of
7227 * strings to sort and then calls msort (short for merge sort) to do the
7228 * work.
7229 */
7230static struct strlist *
7231expsort(struct strlist *str)
7232{
7233 int len;
7234 struct strlist *sp;
7235
7236 len = 0;
7237 for (sp = str; sp; sp = sp->next)
7238 len++;
7239 return msort(str, len);
7240}
7241
7242static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007243expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007244{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007245 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007246 '*', '?', '[', 0
7247 };
7248 /* TODO - EXP_REDIR */
7249
7250 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007251 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007252 struct strlist **savelastp;
7253 struct strlist *sp;
7254 char *p;
7255
7256 if (fflag)
7257 goto nometa;
7258 if (!strpbrk(str->text, metachars))
7259 goto nometa;
7260 savelastp = exparg.lastp;
7261
7262 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007263 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007264 {
7265 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007266//BUGGY estimation of how long expanded name can be
7267 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007268 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007269 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007270 free(expdir);
7271 if (p != str->text)
7272 free(p);
7273 INT_ON;
7274 if (exparg.lastp == savelastp) {
7275 /*
7276 * no matches
7277 */
7278 nometa:
7279 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007280 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007281 exparg.lastp = &str->next;
7282 } else {
7283 *exparg.lastp = NULL;
7284 *savelastp = sp = expsort(*savelastp);
7285 while (sp->next != NULL)
7286 sp = sp->next;
7287 exparg.lastp = &sp->next;
7288 }
7289 str = str->next;
7290 }
7291}
Denys Vlasenko514b51d2016-10-01 14:33:08 +02007292#endif /* ENABLE_ASH_INTERNAL_GLOB */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007293
7294/*
7295 * Perform variable substitution and command substitution on an argument,
7296 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7297 * perform splitting and file name expansion. When arglist is NULL, perform
7298 * here document expansion.
7299 */
7300static void
7301expandarg(union node *arg, struct arglist *arglist, int flag)
7302{
7303 struct strlist *sp;
7304 char *p;
7305
7306 argbackq = arg->narg.backquote;
7307 STARTSTACKSTR(expdest);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007308 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007309 argstr(arg->narg.text, flag,
7310 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007311 p = _STPUTC('\0', expdest);
7312 expdest = p - 1;
7313 if (arglist == NULL) {
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007314 /* here document expanded */
7315 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007316 }
7317 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007318 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007319 exparg.lastp = &exparg.list;
7320 /*
7321 * TODO - EXP_REDIR
7322 */
7323 if (flag & EXP_FULL) {
7324 ifsbreakup(p, &exparg);
7325 *exparg.lastp = NULL;
7326 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007327 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007328 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007329 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007330 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007331 TRACE(("expandarg: rmescapes:'%s'\n", p));
7332 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007333 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007334 sp->text = p;
7335 *exparg.lastp = sp;
7336 exparg.lastp = &sp->next;
7337 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007338 *exparg.lastp = NULL;
7339 if (exparg.list) {
7340 *arglist->lastp = exparg.list;
7341 arglist->lastp = exparg.lastp;
7342 }
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007343
7344 out:
7345 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007346}
7347
7348/*
7349 * Expand shell variables and backquotes inside a here document.
7350 */
7351static void
7352expandhere(union node *arg, int fd)
7353{
Ron Yorston549deab2015-05-18 09:57:51 +02007354 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007355 full_write(fd, stackblock(), expdest - (char *)stackblock());
7356}
7357
7358/*
7359 * Returns true if the pattern matches the string.
7360 */
7361static int
7362patmatch(char *pattern, const char *string)
7363{
Ron Yorston549deab2015-05-18 09:57:51 +02007364 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007365}
7366
7367/*
7368 * See if a pattern matches in a case statement.
7369 */
7370static int
7371casematch(union node *pattern, char *val)
7372{
7373 struct stackmark smark;
7374 int result;
7375
7376 setstackmark(&smark);
7377 argbackq = pattern->narg.backquote;
7378 STARTSTACKSTR(expdest);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007379 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7380 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007381 STACKSTRNUL(expdest);
Denys Vlasenko5ac04f22016-10-27 14:46:50 +02007382 ifsfree();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007383 result = patmatch(stackblock(), val);
7384 popstackmark(&smark);
7385 return result;
7386}
7387
7388
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007389/* ============ find_command */
7390
7391struct builtincmd {
7392 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007393 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007394 /* unsigned flags; */
7395};
7396#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007397/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007398 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007399#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007400#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007401
7402struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007403 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007404 union param {
7405 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007406 /* index >= 0 for commands without path (slashes) */
7407 /* (TODO: what exactly does the value mean? PATH position?) */
7408 /* index == -1 for commands with slashes */
7409 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007410 const struct builtincmd *cmd;
7411 struct funcnode *func;
7412 } u;
7413};
7414/* values of cmdtype */
7415#define CMDUNKNOWN -1 /* no entry in table for command */
7416#define CMDNORMAL 0 /* command is an executable program */
7417#define CMDFUNCTION 1 /* command is a shell function */
7418#define CMDBUILTIN 2 /* command is a shell builtin */
7419
7420/* action to find_command() */
7421#define DO_ERR 0x01 /* prints errors */
7422#define DO_ABS 0x02 /* checks absolute paths */
7423#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7424#define DO_ALTPATH 0x08 /* using alternate path */
7425#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7426
7427static void find_command(char *, struct cmdentry *, int, const char *);
7428
7429
7430/* ============ Hashing commands */
7431
7432/*
7433 * When commands are first encountered, they are entered in a hash table.
7434 * This ensures that a full path search will not have to be done for them
7435 * on each invocation.
7436 *
7437 * We should investigate converting to a linear search, even though that
7438 * would make the command name "hash" a misnomer.
7439 */
7440
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007441struct tblentry {
7442 struct tblentry *next; /* next entry in hash chain */
7443 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007444 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007445 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007446 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007447};
7448
Denis Vlasenko01631112007-12-16 17:20:38 +00007449static struct tblentry **cmdtable;
7450#define INIT_G_cmdtable() do { \
7451 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7452} while (0)
7453
7454static int builtinloc = -1; /* index in path of %builtin, or -1 */
7455
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007456
7457static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007458tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007459{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007460#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007461 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007462 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007463 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007464 while (*envp)
7465 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007466 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007467 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007468 /* re-exec ourselves with the new arguments */
7469 execve(bb_busybox_exec_path, argv, envp);
7470 /* If they called chroot or otherwise made the binary no longer
7471 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007472 }
7473#endif
7474
7475 repeat:
7476#ifdef SYSV
7477 do {
7478 execve(cmd, argv, envp);
7479 } while (errno == EINTR);
7480#else
7481 execve(cmd, argv, envp);
7482#endif
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007483 if (cmd != (char*) bb_busybox_exec_path && errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007484 /* Run "cmd" as a shell script:
7485 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7486 * "If the execve() function fails with ENOEXEC, the shell
7487 * shall execute a command equivalent to having a shell invoked
7488 * with the command name as its first operand,
7489 * with any remaining arguments passed to the new shell"
7490 *
7491 * That is, do not use $SHELL, user's shell, or /bin/sh;
7492 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007493 *
7494 * Note that bash reads ~80 chars of the file, and if it sees
7495 * a zero byte before it sees newline, it doesn't try to
7496 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007497 * message and exit code 126. For one, this prevents attempts
7498 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007499 */
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007500 argv[0] = cmd;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007501 cmd = (char*) bb_busybox_exec_path;
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007502 /* NB: this is only possible because all callers of shellexec()
7503 * ensure that the argv[-1] slot exists!
7504 */
7505 argv--;
7506 argv[0] = (char*) "ash";
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007507 goto repeat;
7508 }
7509}
7510
7511/*
7512 * Exec a program. Never returns. If you change this routine, you may
7513 * have to change the find_command routine as well.
Denys Vlasenko65a8b852016-10-26 22:29:11 +02007514 * argv[-1] must exist and be writable! See tryexec() for why.
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007515 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007516static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007517static void
7518shellexec(char **argv, const char *path, int idx)
7519{
7520 char *cmdname;
7521 int e;
7522 char **envp;
7523 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007524 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007525
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007526 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007527 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007528#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007529 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007530#endif
7531 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007532 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007533 if (applet_no >= 0) {
7534 /* We tried execing ourself, but it didn't work.
7535 * Maybe /proc/self/exe doesn't exist?
7536 * Try $PATH search.
7537 */
7538 goto try_PATH;
7539 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007540 e = errno;
7541 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007542 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007543 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007544 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007545 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007546 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007547 if (errno != ENOENT && errno != ENOTDIR)
7548 e = errno;
7549 }
7550 stunalloc(cmdname);
7551 }
7552 }
7553
7554 /* Map to POSIX errors */
7555 switch (e) {
7556 case EACCES:
7557 exerrno = 126;
7558 break;
7559 case ENOENT:
7560 exerrno = 127;
7561 break;
7562 default:
7563 exerrno = 2;
7564 break;
7565 }
7566 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007567 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7568 argv[0], e, suppress_int));
Denys Vlasenko061a0902016-10-25 17:24:25 +02007569 ash_msg_and_raise(EXEXIT, "%s: %s", argv[0], errmsg(e, "not found"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007570 /* NOTREACHED */
7571}
7572
7573static void
7574printentry(struct tblentry *cmdp)
7575{
7576 int idx;
7577 const char *path;
7578 char *name;
7579
7580 idx = cmdp->param.index;
7581 path = pathval();
7582 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007583 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007584 stunalloc(name);
7585 } while (--idx >= 0);
7586 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7587}
7588
7589/*
7590 * Clear out command entries. The argument specifies the first entry in
7591 * PATH which has changed.
7592 */
7593static void
7594clearcmdentry(int firstchange)
7595{
7596 struct tblentry **tblp;
7597 struct tblentry **pp;
7598 struct tblentry *cmdp;
7599
7600 INT_OFF;
7601 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7602 pp = tblp;
7603 while ((cmdp = *pp) != NULL) {
7604 if ((cmdp->cmdtype == CMDNORMAL &&
7605 cmdp->param.index >= firstchange)
7606 || (cmdp->cmdtype == CMDBUILTIN &&
7607 builtinloc >= firstchange)
7608 ) {
7609 *pp = cmdp->next;
7610 free(cmdp);
7611 } else {
7612 pp = &cmdp->next;
7613 }
7614 }
7615 }
7616 INT_ON;
7617}
7618
7619/*
7620 * Locate a command in the command hash table. If "add" is nonzero,
7621 * add the command to the table if it is not already present. The
7622 * variable "lastcmdentry" is set to point to the address of the link
7623 * pointing to the entry, so that delete_cmd_entry can delete the
7624 * entry.
7625 *
7626 * Interrupts must be off if called with add != 0.
7627 */
7628static struct tblentry **lastcmdentry;
7629
7630static struct tblentry *
7631cmdlookup(const char *name, int add)
7632{
7633 unsigned int hashval;
7634 const char *p;
7635 struct tblentry *cmdp;
7636 struct tblentry **pp;
7637
7638 p = name;
7639 hashval = (unsigned char)*p << 4;
7640 while (*p)
7641 hashval += (unsigned char)*p++;
7642 hashval &= 0x7FFF;
7643 pp = &cmdtable[hashval % CMDTABLESIZE];
7644 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7645 if (strcmp(cmdp->cmdname, name) == 0)
7646 break;
7647 pp = &cmdp->next;
7648 }
7649 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007650 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7651 + strlen(name)
7652 /* + 1 - already done because
7653 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007654 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007655 cmdp->cmdtype = CMDUNKNOWN;
7656 strcpy(cmdp->cmdname, name);
7657 }
7658 lastcmdentry = pp;
7659 return cmdp;
7660}
7661
7662/*
7663 * Delete the command entry returned on the last lookup.
7664 */
7665static void
7666delete_cmd_entry(void)
7667{
7668 struct tblentry *cmdp;
7669
7670 INT_OFF;
7671 cmdp = *lastcmdentry;
7672 *lastcmdentry = cmdp->next;
7673 if (cmdp->cmdtype == CMDFUNCTION)
7674 freefunc(cmdp->param.func);
7675 free(cmdp);
7676 INT_ON;
7677}
7678
7679/*
7680 * Add a new command entry, replacing any existing command entry for
7681 * the same name - except special builtins.
7682 */
7683static void
7684addcmdentry(char *name, struct cmdentry *entry)
7685{
7686 struct tblentry *cmdp;
7687
7688 cmdp = cmdlookup(name, 1);
7689 if (cmdp->cmdtype == CMDFUNCTION) {
7690 freefunc(cmdp->param.func);
7691 }
7692 cmdp->cmdtype = entry->cmdtype;
7693 cmdp->param = entry->u;
7694 cmdp->rehash = 0;
7695}
7696
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007697static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007698hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007699{
7700 struct tblentry **pp;
7701 struct tblentry *cmdp;
7702 int c;
7703 struct cmdentry entry;
7704 char *name;
7705
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007706 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007707 clearcmdentry(0);
7708 return 0;
7709 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007710
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007711 if (*argptr == NULL) {
7712 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7713 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7714 if (cmdp->cmdtype == CMDNORMAL)
7715 printentry(cmdp);
7716 }
7717 }
7718 return 0;
7719 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007720
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007721 c = 0;
7722 while ((name = *argptr) != NULL) {
7723 cmdp = cmdlookup(name, 0);
7724 if (cmdp != NULL
7725 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007726 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7727 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007728 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007729 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007730 find_command(name, &entry, DO_ERR, pathval());
7731 if (entry.cmdtype == CMDUNKNOWN)
7732 c = 1;
7733 argptr++;
7734 }
7735 return c;
7736}
7737
7738/*
7739 * Called when a cd is done. Marks all commands so the next time they
7740 * are executed they will be rehashed.
7741 */
7742static void
7743hashcd(void)
7744{
7745 struct tblentry **pp;
7746 struct tblentry *cmdp;
7747
7748 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7749 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007750 if (cmdp->cmdtype == CMDNORMAL
7751 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007752 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007753 && builtinloc > 0)
7754 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007755 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007756 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007757 }
7758 }
7759}
7760
7761/*
7762 * Fix command hash table when PATH changed.
7763 * Called before PATH is changed. The argument is the new value of PATH;
7764 * pathval() still returns the old value at this point.
7765 * Called with interrupts off.
7766 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007767static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007768changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007769{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007770 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007771 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007772 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007773 int idx_bltin;
7774
7775 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007776 firstchange = 9999; /* assume no change */
7777 idx = 0;
7778 idx_bltin = -1;
7779 for (;;) {
7780 if (*old != *new) {
7781 firstchange = idx;
7782 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007783 || (*old == ':' && *new == '\0')
7784 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007785 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007786 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007787 old = new; /* ignore subsequent differences */
7788 }
7789 if (*new == '\0')
7790 break;
7791 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7792 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007793 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007794 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007795 new++;
7796 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007797 }
7798 if (builtinloc < 0 && idx_bltin >= 0)
7799 builtinloc = idx_bltin; /* zap builtins */
7800 if (builtinloc >= 0 && idx_bltin < 0)
7801 firstchange = 0;
7802 clearcmdentry(firstchange);
7803 builtinloc = idx_bltin;
7804}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007805enum {
7806 TEOF,
7807 TNL,
7808 TREDIR,
7809 TWORD,
7810 TSEMI,
7811 TBACKGND,
7812 TAND,
7813 TOR,
7814 TPIPE,
7815 TLP,
7816 TRP,
7817 TENDCASE,
7818 TENDBQUOTE,
7819 TNOT,
7820 TCASE,
7821 TDO,
7822 TDONE,
7823 TELIF,
7824 TELSE,
7825 TESAC,
7826 TFI,
7827 TFOR,
7828#if ENABLE_ASH_BASH_COMPAT
7829 TFUNCTION,
7830#endif
7831 TIF,
7832 TIN,
7833 TTHEN,
7834 TUNTIL,
7835 TWHILE,
7836 TBEGIN,
7837 TEND
7838};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007839typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007840
Denys Vlasenko888527c2016-10-02 16:54:17 +02007841/* Nth bit indicates if token marks the end of a list */
7842enum {
7843 tokendlist = 0
7844 /* 0 */ | (1u << TEOF)
7845 /* 1 */ | (0u << TNL)
7846 /* 2 */ | (0u << TREDIR)
7847 /* 3 */ | (0u << TWORD)
7848 /* 4 */ | (0u << TSEMI)
7849 /* 5 */ | (0u << TBACKGND)
7850 /* 6 */ | (0u << TAND)
7851 /* 7 */ | (0u << TOR)
7852 /* 8 */ | (0u << TPIPE)
7853 /* 9 */ | (0u << TLP)
7854 /* 10 */ | (1u << TRP)
7855 /* 11 */ | (1u << TENDCASE)
7856 /* 12 */ | (1u << TENDBQUOTE)
7857 /* 13 */ | (0u << TNOT)
7858 /* 14 */ | (0u << TCASE)
7859 /* 15 */ | (1u << TDO)
7860 /* 16 */ | (1u << TDONE)
7861 /* 17 */ | (1u << TELIF)
7862 /* 18 */ | (1u << TELSE)
7863 /* 19 */ | (1u << TESAC)
7864 /* 20 */ | (1u << TFI)
7865 /* 21 */ | (0u << TFOR)
7866#if ENABLE_ASH_BASH_COMPAT
7867 /* 22 */ | (0u << TFUNCTION)
Denys Vlasenko80729a42016-10-02 22:33:15 +02007868#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007869 /* 23 */ | (0u << TIF)
7870 /* 24 */ | (0u << TIN)
7871 /* 25 */ | (1u << TTHEN)
7872 /* 26 */ | (0u << TUNTIL)
7873 /* 27 */ | (0u << TWHILE)
7874 /* 28 */ | (0u << TBEGIN)
7875 /* 29 */ | (1u << TEND)
7876 , /* thus far 29 bits used */
7877};
7878
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007879static const char *const tokname_array[] = {
Denys Vlasenko888527c2016-10-02 16:54:17 +02007880 "end of file",
7881 "newline",
7882 "redirection",
7883 "word",
7884 ";",
7885 "&",
7886 "&&",
7887 "||",
7888 "|",
7889 "(",
7890 ")",
7891 ";;",
7892 "`",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007893#define KWDOFFSET 13
7894 /* the following are keywords */
Denys Vlasenko888527c2016-10-02 16:54:17 +02007895 "!",
7896 "case",
7897 "do",
7898 "done",
7899 "elif",
7900 "else",
7901 "esac",
7902 "fi",
7903 "for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007904#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko888527c2016-10-02 16:54:17 +02007905 "function",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007906#endif
Denys Vlasenko888527c2016-10-02 16:54:17 +02007907 "if",
7908 "in",
7909 "then",
7910 "until",
7911 "while",
7912 "{",
7913 "}",
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007914};
7915
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007916/* Wrapper around strcmp for qsort/bsearch/... */
7917static int
7918pstrcmp(const void *a, const void *b)
7919{
Denys Vlasenko888527c2016-10-02 16:54:17 +02007920 return strcmp((char*)a, *(char**)b);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007921}
7922
7923static const char *const *
7924findkwd(const char *s)
7925{
7926 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007927 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7928 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007929}
7930
7931/*
7932 * Locate and print what a word is...
7933 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007934static int
Ron Yorston3f221112015-08-03 13:47:33 +01007935describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007936{
7937 struct cmdentry entry;
7938 struct tblentry *cmdp;
7939#if ENABLE_ASH_ALIAS
7940 const struct alias *ap;
7941#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007942
7943 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007944
7945 if (describe_command_verbose) {
7946 out1str(command);
7947 }
7948
7949 /* First look at the keywords */
7950 if (findkwd(command)) {
7951 out1str(describe_command_verbose ? " is a shell keyword" : command);
7952 goto out;
7953 }
7954
7955#if ENABLE_ASH_ALIAS
7956 /* Then look at the aliases */
7957 ap = lookupalias(command, 0);
7958 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007959 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007960 out1str("alias ");
7961 printalias(ap);
7962 return 0;
7963 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007964 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007965 goto out;
7966 }
7967#endif
7968 /* Then check if it is a tracked alias */
7969 cmdp = cmdlookup(command, 0);
7970 if (cmdp != NULL) {
7971 entry.cmdtype = cmdp->cmdtype;
7972 entry.u = cmdp->param;
7973 } else {
7974 /* Finally use brute force */
7975 find_command(command, &entry, DO_ABS, path);
7976 }
7977
7978 switch (entry.cmdtype) {
7979 case CMDNORMAL: {
7980 int j = entry.u.index;
7981 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007982 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007983 p = command;
7984 } else {
7985 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007986 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007987 stunalloc(p);
7988 } while (--j >= 0);
7989 }
7990 if (describe_command_verbose) {
7991 out1fmt(" is%s %s",
7992 (cmdp ? " a tracked alias for" : nullstr), p
7993 );
7994 } else {
7995 out1str(p);
7996 }
7997 break;
7998 }
7999
8000 case CMDFUNCTION:
8001 if (describe_command_verbose) {
8002 out1str(" is a shell function");
8003 } else {
8004 out1str(command);
8005 }
8006 break;
8007
8008 case CMDBUILTIN:
8009 if (describe_command_verbose) {
8010 out1fmt(" is a %sshell builtin",
8011 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
8012 "special " : nullstr
8013 );
8014 } else {
8015 out1str(command);
8016 }
8017 break;
8018
8019 default:
8020 if (describe_command_verbose) {
8021 out1str(": not found\n");
8022 }
8023 return 127;
8024 }
8025 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008026 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008027 return 0;
8028}
8029
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008030static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008031typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008032{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008033 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008034 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008035 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008036
Denis Vlasenko46846e22007-05-20 13:08:31 +00008037 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008038 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008039 i++;
8040 verbose = 0;
8041 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008042 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008043 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008044 }
8045 return err;
8046}
8047
8048#if ENABLE_ASH_CMDCMD
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008049/* Is it "command [-p] PROG ARGS" bltin, no other opts? Return ptr to "PROG" if yes */
8050static char **
8051parse_command_args(char **argv, const char **path)
8052{
8053 char *cp, c;
8054
8055 for (;;) {
8056 cp = *++argv;
8057 if (!cp)
8058 return NULL;
8059 if (*cp++ != '-')
8060 break;
8061 c = *cp++;
8062 if (!c)
8063 break;
8064 if (c == '-' && !*cp) {
8065 if (!*++argv)
8066 return NULL;
8067 break;
8068 }
8069 do {
8070 switch (c) {
8071 case 'p':
8072 *path = bb_default_path;
8073 break;
8074 default:
8075 /* run 'typecmd' for other options */
8076 return NULL;
8077 }
8078 c = *cp++;
8079 } while (c);
8080 }
8081 return argv;
8082}
8083
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008084static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008085commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008086{
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008087 char *cmd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008088 int c;
8089 enum {
8090 VERIFY_BRIEF = 1,
8091 VERIFY_VERBOSE = 2,
8092 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008093 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008094
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008095 /* "command [-p] PROG ARGS" (that is, without -V or -v)
8096 * never reaches this function.
8097 */
8098
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008099 while ((c = nextopt("pvV")) != '\0')
8100 if (c == 'V')
8101 verify |= VERIFY_VERBOSE;
8102 else if (c == 'v')
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008103 /*verify |= VERIFY_BRIEF*/;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008104#if DEBUG
8105 else if (c != 'p')
8106 abort();
8107#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008108 else
8109 path = bb_default_path;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008110
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008111 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
Denys Vlasenkocac4d002016-10-01 03:02:25 +02008112 cmd = *argptr;
8113 if (/*verify && */ cmd)
8114 return describe_command(cmd, path, verify /* - VERIFY_BRIEF*/);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008115
8116 return 0;
8117}
8118#endif
8119
8120
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008121/*static int funcblocksize; // size of structures in function */
8122/*static int funcstringsize; // size of strings in node */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008123static void *funcblock; /* block to allocate function from */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008124static char *funcstring_end; /* end of block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008125
Eric Andersencb57d552001-06-28 07:25:16 +00008126/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008127#define EV_EXIT 01 /* exit after evaluating tree */
8128#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008129
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008130static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008131 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8132 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8133 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8134 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8135 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8136 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8137 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8138 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8139 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8140 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8141 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8142 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8143 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8144 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8145 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8146 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8147 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008148#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008149 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008150#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008151 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8152 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8153 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8154 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8155 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8156 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8157 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8158 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8159 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008160};
8161
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008162static int calcsize(int funcblocksize, union node *n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008163
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008164static int
8165sizenodelist(int funcblocksize, struct nodelist *lp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008166{
8167 while (lp) {
8168 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008169 funcblocksize = calcsize(funcblocksize, lp->n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008170 lp = lp->next;
8171 }
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008172 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008173}
8174
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008175static int
8176calcsize(int funcblocksize, union node *n)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008177{
8178 if (n == NULL)
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008179 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008180 funcblocksize += nodesize[n->type];
8181 switch (n->type) {
8182 case NCMD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008183 funcblocksize = calcsize(funcblocksize, n->ncmd.redirect);
8184 funcblocksize = calcsize(funcblocksize, n->ncmd.args);
8185 funcblocksize = calcsize(funcblocksize, n->ncmd.assign);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008186 break;
8187 case NPIPE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008188 funcblocksize = sizenodelist(funcblocksize, n->npipe.cmdlist);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008189 break;
8190 case NREDIR:
8191 case NBACKGND:
8192 case NSUBSHELL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008193 funcblocksize = calcsize(funcblocksize, n->nredir.redirect);
8194 funcblocksize = calcsize(funcblocksize, n->nredir.n);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008195 break;
8196 case NAND:
8197 case NOR:
8198 case NSEMI:
8199 case NWHILE:
8200 case NUNTIL:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008201 funcblocksize = calcsize(funcblocksize, n->nbinary.ch2);
8202 funcblocksize = calcsize(funcblocksize, n->nbinary.ch1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008203 break;
8204 case NIF:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008205 funcblocksize = calcsize(funcblocksize, n->nif.elsepart);
8206 funcblocksize = calcsize(funcblocksize, n->nif.ifpart);
8207 funcblocksize = calcsize(funcblocksize, n->nif.test);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008208 break;
8209 case NFOR:
Denys Vlasenko561639a2016-10-07 04:28:33 +02008210 funcblocksize += SHELL_ALIGN(strlen(n->nfor.var) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008211 funcblocksize = calcsize(funcblocksize, n->nfor.body);
8212 funcblocksize = calcsize(funcblocksize, n->nfor.args);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008213 break;
8214 case NCASE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008215 funcblocksize = calcsize(funcblocksize, n->ncase.cases);
8216 funcblocksize = calcsize(funcblocksize, n->ncase.expr);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008217 break;
8218 case NCLIST:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008219 funcblocksize = calcsize(funcblocksize, n->nclist.body);
8220 funcblocksize = calcsize(funcblocksize, n->nclist.pattern);
8221 funcblocksize = calcsize(funcblocksize, n->nclist.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008222 break;
8223 case NDEFUN:
8224 case NARG:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008225 funcblocksize = sizenodelist(funcblocksize, n->narg.backquote);
Denys Vlasenko561639a2016-10-07 04:28:33 +02008226 funcblocksize += SHELL_ALIGN(strlen(n->narg.text) + 1); /* was funcstringsize += ... */
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008227 funcblocksize = calcsize(funcblocksize, n->narg.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008228 break;
8229 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008230#if ENABLE_ASH_BASH_COMPAT
8231 case NTO2:
8232#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008233 case NCLOBBER:
8234 case NFROM:
8235 case NFROMTO:
8236 case NAPPEND:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008237 funcblocksize = calcsize(funcblocksize, n->nfile.fname);
8238 funcblocksize = calcsize(funcblocksize, n->nfile.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008239 break;
8240 case NTOFD:
8241 case NFROMFD:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008242 funcblocksize = calcsize(funcblocksize, n->ndup.vname);
8243 funcblocksize = calcsize(funcblocksize, n->ndup.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008244 break;
8245 case NHERE:
8246 case NXHERE:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008247 funcblocksize = calcsize(funcblocksize, n->nhere.doc);
8248 funcblocksize = calcsize(funcblocksize, n->nhere.next);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008249 break;
8250 case NNOT:
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008251 funcblocksize = calcsize(funcblocksize, n->nnot.com);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008252 break;
8253 };
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008254 return funcblocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008255}
8256
8257static char *
8258nodeckstrdup(char *s)
8259{
Denys Vlasenko561639a2016-10-07 04:28:33 +02008260 funcstring_end -= SHELL_ALIGN(strlen(s) + 1);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008261 return strcpy(funcstring_end, s);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008262}
8263
8264static union node *copynode(union node *);
8265
8266static struct nodelist *
8267copynodelist(struct nodelist *lp)
8268{
8269 struct nodelist *start;
8270 struct nodelist **lpp;
8271
8272 lpp = &start;
8273 while (lp) {
8274 *lpp = funcblock;
8275 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8276 (*lpp)->n = copynode(lp->n);
8277 lp = lp->next;
8278 lpp = &(*lpp)->next;
8279 }
8280 *lpp = NULL;
8281 return start;
8282}
8283
8284static union node *
8285copynode(union node *n)
8286{
8287 union node *new;
8288
8289 if (n == NULL)
8290 return NULL;
8291 new = funcblock;
8292 funcblock = (char *) funcblock + nodesize[n->type];
8293
8294 switch (n->type) {
8295 case NCMD:
8296 new->ncmd.redirect = copynode(n->ncmd.redirect);
8297 new->ncmd.args = copynode(n->ncmd.args);
8298 new->ncmd.assign = copynode(n->ncmd.assign);
8299 break;
8300 case NPIPE:
8301 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008302 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008303 break;
8304 case NREDIR:
8305 case NBACKGND:
8306 case NSUBSHELL:
8307 new->nredir.redirect = copynode(n->nredir.redirect);
8308 new->nredir.n = copynode(n->nredir.n);
8309 break;
8310 case NAND:
8311 case NOR:
8312 case NSEMI:
8313 case NWHILE:
8314 case NUNTIL:
8315 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8316 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8317 break;
8318 case NIF:
8319 new->nif.elsepart = copynode(n->nif.elsepart);
8320 new->nif.ifpart = copynode(n->nif.ifpart);
8321 new->nif.test = copynode(n->nif.test);
8322 break;
8323 case NFOR:
8324 new->nfor.var = nodeckstrdup(n->nfor.var);
8325 new->nfor.body = copynode(n->nfor.body);
8326 new->nfor.args = copynode(n->nfor.args);
8327 break;
8328 case NCASE:
8329 new->ncase.cases = copynode(n->ncase.cases);
8330 new->ncase.expr = copynode(n->ncase.expr);
8331 break;
8332 case NCLIST:
8333 new->nclist.body = copynode(n->nclist.body);
8334 new->nclist.pattern = copynode(n->nclist.pattern);
8335 new->nclist.next = copynode(n->nclist.next);
8336 break;
8337 case NDEFUN:
8338 case NARG:
8339 new->narg.backquote = copynodelist(n->narg.backquote);
8340 new->narg.text = nodeckstrdup(n->narg.text);
8341 new->narg.next = copynode(n->narg.next);
8342 break;
8343 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008344#if ENABLE_ASH_BASH_COMPAT
8345 case NTO2:
8346#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008347 case NCLOBBER:
8348 case NFROM:
8349 case NFROMTO:
8350 case NAPPEND:
8351 new->nfile.fname = copynode(n->nfile.fname);
8352 new->nfile.fd = n->nfile.fd;
8353 new->nfile.next = copynode(n->nfile.next);
8354 break;
8355 case NTOFD:
8356 case NFROMFD:
8357 new->ndup.vname = copynode(n->ndup.vname);
8358 new->ndup.dupfd = n->ndup.dupfd;
8359 new->ndup.fd = n->ndup.fd;
8360 new->ndup.next = copynode(n->ndup.next);
8361 break;
8362 case NHERE:
8363 case NXHERE:
8364 new->nhere.doc = copynode(n->nhere.doc);
8365 new->nhere.fd = n->nhere.fd;
8366 new->nhere.next = copynode(n->nhere.next);
8367 break;
8368 case NNOT:
8369 new->nnot.com = copynode(n->nnot.com);
8370 break;
8371 };
8372 new->type = n->type;
8373 return new;
8374}
8375
8376/*
8377 * Make a copy of a parse tree.
8378 */
8379static struct funcnode *
8380copyfunc(union node *n)
8381{
8382 struct funcnode *f;
8383 size_t blocksize;
8384
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008385 /*funcstringsize = 0;*/
8386 blocksize = offsetof(struct funcnode, n) + calcsize(0, n);
8387 f = ckzalloc(blocksize /* + funcstringsize */);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008388 funcblock = (char *) f + offsetof(struct funcnode, n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008389 funcstring_end = (char *) f + blocksize;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008390 copynode(n);
Denys Vlasenko4c438b52016-10-07 04:05:15 +02008391 /* f->count = 0; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008392 return f;
8393}
8394
8395/*
8396 * Define a shell function.
8397 */
8398static void
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008399defun(union node *func)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008400{
8401 struct cmdentry entry;
8402
8403 INT_OFF;
8404 entry.cmdtype = CMDFUNCTION;
8405 entry.u.func = copyfunc(func);
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008406 addcmdentry(func->narg.text, &entry);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008407 INT_ON;
8408}
8409
Denis Vlasenko4b875702009-03-19 13:30:04 +00008410/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008411#define SKIPBREAK (1 << 0)
8412#define SKIPCONT (1 << 1)
8413#define SKIPFUNC (1 << 2)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008414static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008415static int skipcount; /* number of levels to skip */
8416static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008417static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008418
Denis Vlasenko4b875702009-03-19 13:30:04 +00008419/* Forward decl way out to parsing code - dotrap needs it */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008420static int evalstring(char *s, int flags);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008421
Denis Vlasenko4b875702009-03-19 13:30:04 +00008422/* Called to execute a trap.
8423 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008424 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008425 *
8426 * Perhaps we should avoid entering new trap handlers
8427 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008428 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008429static void
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008430dotrap(void)
8431{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008432 uint8_t *g;
8433 int sig;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008434 uint8_t last_status;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008435
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008436 if (!pending_sig)
8437 return;
8438
8439 last_status = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008440 pending_sig = 0;
Denys Vlasenkode892052016-10-02 01:49:13 +02008441 barrier();
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008442
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008443 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008444 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008445 char *p;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008446
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008447 if (!*g)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008448 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008449
8450 if (evalskip) {
8451 pending_sig = sig;
8452 break;
8453 }
8454
8455 p = trap[sig];
Denis Vlasenko4b875702009-03-19 13:30:04 +00008456 /* non-trapped SIGINT is handled separately by raise_interrupt,
8457 * don't upset it by resetting gotsig[SIGINT-1] */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008458 if (sig == SIGINT && !p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008459 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008460
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008461 TRACE(("sig %d is active, will run handler '%s'\n", sig, p));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008462 *g = 0;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008463 if (!p)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008464 continue;
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008465 evalstring(p, 0);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008466 }
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008467 exitstatus = last_status;
8468 TRACE(("dotrap returns\n"));
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008469}
8470
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008471/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008472static int evalloop(union node *, int);
8473static int evalfor(union node *, int);
8474static int evalcase(union node *, int);
8475static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008476static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008477static int evalpipe(union node *, int);
8478static int evalcommand(union node *, int);
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02008479static int evalbltin(const struct builtincmd *, int, char **, int);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008480static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008481
Eric Andersen62483552001-07-10 06:09:16 +00008482/*
Eric Andersenc470f442003-07-28 09:56:35 +00008483 * Evaluate a parse tree. The value is left in the global variable
8484 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008485 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008486static int
Eric Andersenc470f442003-07-28 09:56:35 +00008487evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008488{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008489 struct jmploc *volatile savehandler = exception_handler;
8490 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008491 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008492 int (*evalfn)(union node *, int);
8493 int status = 0;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008494 int int_level;
8495
8496 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008497
Eric Andersenc470f442003-07-28 09:56:35 +00008498 if (n == NULL) {
8499 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008500 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008501 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008502 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008503
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008504 dotrap();
8505
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008506 exception_handler = &jmploc;
8507 {
8508 int err = setjmp(jmploc.loc);
8509 if (err) {
8510 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008511 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008512 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8513 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008514 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008515 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008516 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008517 TRACE(("exception %d in evaltree, propagating err=%d\n",
8518 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008519 exception_handler = savehandler;
8520 longjmp(exception_handler->loc, err);
8521 }
8522 }
8523
Eric Andersenc470f442003-07-28 09:56:35 +00008524 switch (n->type) {
8525 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008526#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008527 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008528 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008529 break;
8530#endif
8531 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008532 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008533 goto setstatus;
8534 case NREDIR:
8535 expredir(n->nredir.redirect);
8536 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8537 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008538 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008539 }
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02008540 if (n->nredir.redirect)
8541 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008542 goto setstatus;
8543 case NCMD:
8544 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008545 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008546 if (eflag && !(flags & EV_TESTED))
8547 checkexit = ~0;
8548 goto calleval;
8549 case NFOR:
8550 evalfn = evalfor;
8551 goto calleval;
8552 case NWHILE:
8553 case NUNTIL:
8554 evalfn = evalloop;
8555 goto calleval;
8556 case NSUBSHELL:
8557 case NBACKGND:
8558 evalfn = evalsubshell;
Denys Vlasenkocf98b0c2016-10-25 18:19:39 +02008559 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008560 case NPIPE:
8561 evalfn = evalpipe;
8562 goto checkexit;
8563 case NCASE:
8564 evalfn = evalcase;
8565 goto calleval;
8566 case NAND:
8567 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008568 case NSEMI: {
8569
Eric Andersenc470f442003-07-28 09:56:35 +00008570#if NAND + 1 != NOR
8571#error NAND + 1 != NOR
8572#endif
8573#if NOR + 1 != NSEMI
8574#error NOR + 1 != NSEMI
8575#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008576 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008577 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008578 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008579 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008580 );
Denys Vlasenkobc1a0082016-10-02 15:31:33 +02008581 if ((!status) == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008582 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008583 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008584 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008585 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008586 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008587 status = evalfn(n, flags);
8588 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008589 }
Eric Andersenc470f442003-07-28 09:56:35 +00008590 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008591 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008592 if (evalskip)
8593 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008594 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008595 n = n->nif.ifpart;
8596 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008597 }
8598 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008599 n = n->nif.elsepart;
8600 goto evaln;
8601 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008602 status = 0;
8603 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008604 case NDEFUN:
Denys Vlasenko7aec8682016-10-25 20:26:02 +02008605 defun(n);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008606 /* Not necessary. To test it:
8607 * "false; f() { qwerty; }; echo $?" should print 0.
8608 */
8609 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008610 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008611 exitstatus = status;
8612 break;
8613 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008614
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008615 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008616 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008617
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008618 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008619 /* Order of checks below is important:
8620 * signal handlers trigger before exit caused by "set -e".
8621 */
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008622 dotrap();
8623
8624 if (checkexit & status)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008625 raise_exception(EXEXIT);
Denys Vlasenkob98b4c12016-10-01 23:25:12 +02008626 if (flags & EV_EXIT)
8627 raise_exception(EXEXIT);
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008628
8629 RESTORE_INT(int_level);
8630 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008631
8632 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008633}
8634
Eric Andersenc470f442003-07-28 09:56:35 +00008635#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8636static
8637#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008638int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008639
Denys Vlasenko37dc08b2016-10-02 04:38:07 +02008640static int
8641skiploop(void)
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008642{
8643 int skip = evalskip;
8644
8645 switch (skip) {
8646 case 0:
8647 break;
8648 case SKIPBREAK:
8649 case SKIPCONT:
8650 if (--skipcount <= 0) {
8651 evalskip = 0;
8652 break;
8653 }
8654 skip = SKIPBREAK;
8655 break;
8656 }
8657 return skip;
8658}
8659
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008660static int
Eric Andersenc470f442003-07-28 09:56:35 +00008661evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008662{
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008663 int skip;
Eric Andersencb57d552001-06-28 07:25:16 +00008664 int status;
8665
8666 loopnest++;
8667 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008668 flags &= EV_TESTED;
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008669 do {
Eric Andersenc470f442003-07-28 09:56:35 +00008670 int i;
8671
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008672 i = evaltree(n->nbinary.ch1, EV_TESTED);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008673 skip = skiploop();
8674 if (skip == SKIPFUNC)
8675 status = i;
8676 if (skip)
8677 continue;
Eric Andersenc470f442003-07-28 09:56:35 +00008678 if (n->type != NWHILE)
8679 i = !i;
8680 if (i != 0)
8681 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008682 status = evaltree(n->nbinary.ch2, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008683 skip = skiploop();
8684 } while (!(skip & ~SKIPCONT));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008685 loopnest--;
8686
8687 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008688}
8689
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008690static int
Eric Andersenc470f442003-07-28 09:56:35 +00008691evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008692{
8693 struct arglist arglist;
8694 union node *argp;
8695 struct strlist *sp;
8696 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008697 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008698
8699 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008700 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008701 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008702 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008703 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersencb57d552001-06-28 07:25:16 +00008704 }
8705 *arglist.lastp = NULL;
8706
Eric Andersencb57d552001-06-28 07:25:16 +00008707 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008708 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008709 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008710 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008711 status = evaltree(n->nfor.body, flags);
Denys Vlasenko35ec8182016-10-01 19:56:52 +02008712 if (skiploop() & ~SKIPCONT)
Eric Andersencb57d552001-06-28 07:25:16 +00008713 break;
Eric Andersencb57d552001-06-28 07:25:16 +00008714 }
8715 loopnest--;
Eric Andersencb57d552001-06-28 07:25:16 +00008716 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008717
8718 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008719}
8720
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008721static int
Eric Andersenc470f442003-07-28 09:56:35 +00008722evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008723{
8724 union node *cp;
8725 union node *patp;
8726 struct arglist arglist;
8727 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008728 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008729
8730 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008731 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008732 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008733 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008734 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8735 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008736 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008737 /* Ensure body is non-empty as otherwise
8738 * EV_EXIT may prevent us from setting the
8739 * exit status.
8740 */
8741 if (evalskip == 0 && cp->nclist.body) {
8742 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008743 }
8744 goto out;
8745 }
8746 }
8747 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008748 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008749 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008750
8751 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008752}
8753
Eric Andersenc470f442003-07-28 09:56:35 +00008754/*
8755 * Kick off a subshell to evaluate a tree.
8756 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008757static int
Eric Andersenc470f442003-07-28 09:56:35 +00008758evalsubshell(union node *n, int flags)
8759{
8760 struct job *jp;
8761 int backgnd = (n->type == NBACKGND);
8762 int status;
8763
8764 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008765 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008766 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008767 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008768 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008769 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008770 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008771 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008772 flags |= EV_EXIT;
8773 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008774 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008775 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008776 redirect(n->nredir.redirect, 0);
8777 evaltreenr(n->nredir.n, flags);
8778 /* never returns */
8779 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008780 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00008781 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008782 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008783 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008784 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008785 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008786}
8787
Eric Andersenc470f442003-07-28 09:56:35 +00008788/*
8789 * Compute the names of the files in a redirection list.
8790 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008791static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008792static void
8793expredir(union node *n)
8794{
8795 union node *redir;
8796
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008797 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008798 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008799
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008800 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008801 fn.lastp = &fn.list;
8802 switch (redir->type) {
8803 case NFROMTO:
8804 case NFROM:
8805 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008806#if ENABLE_ASH_BASH_COMPAT
8807 case NTO2:
8808#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008809 case NCLOBBER:
8810 case NAPPEND:
8811 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008812 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008813#if ENABLE_ASH_BASH_COMPAT
8814 store_expfname:
8815#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008816#if 0
8817// By the design of stack allocator, the loop of this kind:
8818// while true; do while true; do break; done </dev/null; done
8819// will look like a memory leak: ash plans to free expfname's
8820// of "/dev/null" as soon as it finishes running the loop
8821// (in this case, never).
8822// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008823 if (redir->nfile.expfname)
8824 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008825// It results in corrupted state of stacked allocations.
8826#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008827 redir->nfile.expfname = fn.list->text;
8828 break;
8829 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008830 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008831 if (redir->ndup.vname) {
8832 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008833 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008834 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008835#if ENABLE_ASH_BASH_COMPAT
8836//FIXME: we used expandarg with different args!
8837 if (!isdigit_str9(fn.list->text)) {
8838 /* >&file, not >&fd */
8839 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8840 ash_msg_and_raise_error("redir error");
8841 redir->type = NTO2;
8842 goto store_expfname;
8843 }
8844#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008845 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008846 }
8847 break;
8848 }
8849 }
8850}
8851
Eric Andersencb57d552001-06-28 07:25:16 +00008852/*
Eric Andersencb57d552001-06-28 07:25:16 +00008853 * Evaluate a pipeline. All the processes in the pipeline are children
8854 * of the process creating the pipeline. (This differs from some versions
8855 * of the shell, which make the last process in a pipeline the parent
8856 * of all the rest.)
8857 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008858static int
Eric Andersenc470f442003-07-28 09:56:35 +00008859evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008860{
8861 struct job *jp;
8862 struct nodelist *lp;
8863 int pipelen;
8864 int prevfd;
8865 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008866 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008867
Eric Andersenc470f442003-07-28 09:56:35 +00008868 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008869 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008870 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008871 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008872 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008873 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008874 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008875 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008876 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008877 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008878 pip[1] = -1;
8879 if (lp->next) {
8880 if (pipe(pip) < 0) {
8881 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008882 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008883 }
8884 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008885 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denys Vlasenko70392332016-10-27 02:31:55 +02008886 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008887 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008888 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008889 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008890 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008891 if (prevfd > 0) {
8892 dup2(prevfd, 0);
8893 close(prevfd);
8894 }
8895 if (pip[1] > 1) {
8896 dup2(pip[1], 1);
8897 close(pip[1]);
8898 }
Eric Andersenc470f442003-07-28 09:56:35 +00008899 evaltreenr(lp->n, flags);
8900 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008901 }
Denys Vlasenko70392332016-10-27 02:31:55 +02008902 /* parent */
Eric Andersencb57d552001-06-28 07:25:16 +00008903 if (prevfd >= 0)
8904 close(prevfd);
8905 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008906 /* Don't want to trigger debugging */
8907 if (pip[1] != -1)
8908 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008909 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008910 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008911 status = waitforjob(jp);
8912 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008913 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008914 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008915
8916 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008917}
8918
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008919/*
8920 * Controls whether the shell is interactive or not.
8921 */
8922static void
8923setinteractive(int on)
8924{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008925 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008926
8927 if (++on == is_interactive)
8928 return;
8929 is_interactive = on;
8930 setsignal(SIGINT);
8931 setsignal(SIGQUIT);
8932 setsignal(SIGTERM);
8933#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8934 if (is_interactive > 1) {
8935 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008936 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008937
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008938 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008939 /* note: ash and hush share this string */
8940 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008941 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8942 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008943 bb_banner,
8944 "built-in shell (ash)"
8945 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008946 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008947 }
8948 }
8949#endif
8950}
8951
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008952static void
8953optschanged(void)
8954{
8955#if DEBUG
8956 opentrace();
8957#endif
8958 setinteractive(iflag);
8959 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008960#if ENABLE_FEATURE_EDITING_VI
8961 if (viflag)
8962 line_input_state->flags |= VI_MODE;
8963 else
8964 line_input_state->flags &= ~VI_MODE;
8965#else
8966 viflag = 0; /* forcibly keep the option off */
8967#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008968}
8969
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008970static struct localvar *localvars;
8971
8972/*
8973 * Called after a function returns.
8974 * Interrupts must be off.
8975 */
8976static void
8977poplocalvars(void)
8978{
8979 struct localvar *lvp;
8980 struct var *vp;
8981
8982 while ((lvp = localvars) != NULL) {
8983 localvars = lvp->next;
8984 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008985 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008986 if (vp == NULL) { /* $- saved */
8987 memcpy(optlist, lvp->text, sizeof(optlist));
8988 free((char*)lvp->text);
8989 optschanged();
8990 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008991 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008992 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008993 if (vp->var_func)
8994 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008995 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008996 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008997 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008998 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008999 }
9000 free(lvp);
9001 }
9002}
9003
9004static int
9005evalfun(struct funcnode *func, int argc, char **argv, int flags)
9006{
9007 volatile struct shparam saveparam;
9008 struct localvar *volatile savelocalvars;
9009 struct jmploc *volatile savehandler;
9010 struct jmploc jmploc;
9011 int e;
9012
9013 saveparam = shellparam;
9014 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009015 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009016 e = setjmp(jmploc.loc);
9017 if (e) {
9018 goto funcdone;
9019 }
9020 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009021 exception_handler = &jmploc;
9022 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00009023 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009024 func->count++;
9025 funcnest++;
9026 INT_ON;
9027 shellparam.nparam = argc - 1;
9028 shellparam.p = argv + 1;
9029#if ENABLE_ASH_GETOPTS
9030 shellparam.optind = 1;
9031 shellparam.optoff = -1;
9032#endif
Denys Vlasenko7aec8682016-10-25 20:26:02 +02009033 evaltree(func->n.narg.next, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00009034 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009035 INT_OFF;
9036 funcnest--;
9037 freefunc(func);
9038 poplocalvars();
9039 localvars = savelocalvars;
9040 freeparam(&shellparam);
9041 shellparam = saveparam;
9042 exception_handler = savehandler;
9043 INT_ON;
9044 evalskip &= ~SKIPFUNC;
9045 return e;
9046}
9047
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009048/*
9049 * Make a variable a local variable. When a variable is made local, it's
9050 * value and flags are saved in a localvar structure. The saved values
9051 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009052 * "-" as a special case: it makes changes to "set +-options" local
9053 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009054 */
9055static void
9056mklocal(char *name)
9057{
9058 struct localvar *lvp;
9059 struct var **vpp;
9060 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009061 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009062
9063 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009064 /* Cater for duplicate "local". Examples:
9065 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9066 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9067 */
9068 lvp = localvars;
9069 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009070 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009071 if (eq)
9072 setvareq(name, 0);
9073 /* else:
9074 * it's a duplicate "local VAR" declaration, do nothing
9075 */
9076 return;
9077 }
9078 lvp = lvp->next;
9079 }
9080
9081 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009082 if (LONE_DASH(name)) {
9083 char *p;
9084 p = ckmalloc(sizeof(optlist));
9085 lvp->text = memcpy(p, optlist, sizeof(optlist));
9086 vp = NULL;
9087 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009088 vpp = hashvar(name);
9089 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009090 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009091 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009092 if (eq)
9093 setvareq(name, VSTRFIXED);
9094 else
9095 setvar(name, NULL, VSTRFIXED);
9096 vp = *vpp; /* the new variable */
9097 lvp->flags = VUNSET;
9098 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009099 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009100 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009101 /* make sure neither "struct var" nor string gets freed
9102 * during (un)setting:
9103 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009104 vp->flags |= VSTRFIXED|VTEXTFIXED;
9105 if (eq)
9106 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009107 else
9108 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009109 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009110 }
9111 }
9112 lvp->vp = vp;
9113 lvp->next = localvars;
9114 localvars = lvp;
9115 INT_ON;
9116}
9117
9118/*
9119 * The "local" command.
9120 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009121static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009122localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009123{
9124 char *name;
9125
Ron Yorstonef2386b2015-10-29 16:19:14 +00009126 if (!funcnest)
9127 ash_msg_and_raise_error("not in a function");
9128
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009129 argv = argptr;
9130 while ((name = *argv++) != NULL) {
9131 mklocal(name);
9132 }
9133 return 0;
9134}
9135
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009136static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009137falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009138{
9139 return 1;
9140}
9141
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009142static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009143truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009144{
9145 return 0;
9146}
9147
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009148static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009149execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009150{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009151 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009152 iflag = 0; /* exit on error */
9153 mflag = 0;
9154 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009155 /* We should set up signals for "exec CMD"
9156 * the same way as for "CMD" without "exec".
9157 * But optschanged->setinteractive->setsignal
9158 * still thought we are a root shell. Therefore, for example,
9159 * SIGQUIT is still set to IGN. Fix it:
9160 */
9161 shlvl++;
9162 setsignal(SIGQUIT);
9163 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9164 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9165 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9166
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009167 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009168 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009169 }
9170 return 0;
9171}
9172
9173/*
9174 * The return command.
9175 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009176static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009177returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009178{
9179 /*
9180 * If called outside a function, do what ksh does;
9181 * skip the rest of the file.
9182 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009183 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009184 return argv[1] ? number(argv[1]) : exitstatus;
9185}
9186
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009187/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009188static int breakcmd(int, char **) FAST_FUNC;
9189static int dotcmd(int, char **) FAST_FUNC;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009190static int evalcmd(int, char **, int) FAST_FUNC;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009191static int exitcmd(int, char **) FAST_FUNC;
9192static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009193#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009194static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009195#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009196#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009197static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009198#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009199#if MAX_HISTORY
9200static int historycmd(int, char **) FAST_FUNC;
9201#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009202#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009203static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009204#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009205static int readcmd(int, char **) FAST_FUNC;
9206static int setcmd(int, char **) FAST_FUNC;
9207static int shiftcmd(int, char **) FAST_FUNC;
9208static int timescmd(int, char **) FAST_FUNC;
9209static int trapcmd(int, char **) FAST_FUNC;
9210static int umaskcmd(int, char **) FAST_FUNC;
9211static int unsetcmd(int, char **) FAST_FUNC;
9212static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009213
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009214#define BUILTIN_NOSPEC "0"
9215#define BUILTIN_SPECIAL "1"
9216#define BUILTIN_REGULAR "2"
9217#define BUILTIN_SPEC_REG "3"
9218#define BUILTIN_ASSIGN "4"
9219#define BUILTIN_SPEC_ASSG "5"
9220#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009221#define BUILTIN_SPEC_REG_ASSG "7"
9222
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009223/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009224#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009225static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009226#endif
9227#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009228static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009229#endif
9230#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009231static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009232#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009233
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009234/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009235static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009236 { BUILTIN_SPEC_REG "." , dotcmd },
9237 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009238#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009239 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009240#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009241 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009242#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009243#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009244#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009245 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009246#endif
9247#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009248 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009249#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009250 { BUILTIN_SPEC_REG "break" , breakcmd },
9251 { BUILTIN_REGULAR "cd" , cdcmd },
9252 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009253#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009254 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009255#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009256 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009257#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009258 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009259#endif
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009260 { BUILTIN_SPEC_REG "eval" , NULL }, /*evalcmd() has a differing prototype*/
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009261 { BUILTIN_SPEC_REG "exec" , execcmd },
9262 { BUILTIN_SPEC_REG "exit" , exitcmd },
9263 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9264 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009265#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009266 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009267#endif
9268#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009269 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009270#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009271 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009272#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009273 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009274#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009275#if MAX_HISTORY
9276 { BUILTIN_NOSPEC "history" , historycmd },
9277#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009278#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009279 { BUILTIN_REGULAR "jobs" , jobscmd },
9280 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009281#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009282#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009283 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009284#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009285 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009286#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009287 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009288#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009289 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9290 { BUILTIN_REGULAR "read" , readcmd },
9291 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9292 { BUILTIN_SPEC_REG "return" , returncmd },
9293 { BUILTIN_SPEC_REG "set" , setcmd },
9294 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009295#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009296 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009297#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009298#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009299 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009300#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009301 { BUILTIN_SPEC_REG "times" , timescmd },
9302 { BUILTIN_SPEC_REG "trap" , trapcmd },
9303 { BUILTIN_REGULAR "true" , truecmd },
9304 { BUILTIN_NOSPEC "type" , typecmd },
9305 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9306 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009307#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009308 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009309#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009310 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9311 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009312};
9313
Denis Vlasenko80591b02008-03-25 07:49:43 +00009314/* Should match the above table! */
9315#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009316 /* . : */ 2 + \
9317 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9318 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9319 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9320 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9321 /* break cd cddir */ 3)
9322#define EVALCMD (COMMANDCMD + \
9323 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9324 /* continue */ 1 + \
9325 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9326 0)
9327#define EXECCMD (EVALCMD + \
9328 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009329
9330/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009331 * Search the table of builtin commands.
9332 */
Denys Vlasenko888527c2016-10-02 16:54:17 +02009333static int
9334pstrcmp1(const void *a, const void *b)
9335{
9336 return strcmp((char*)a, *(char**)b + 1);
9337}
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009338static struct builtincmd *
9339find_builtin(const char *name)
9340{
9341 struct builtincmd *bp;
9342
9343 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009344 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denys Vlasenko888527c2016-10-02 16:54:17 +02009345 pstrcmp1
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009346 );
9347 return bp;
9348}
9349
9350/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009351 * Execute a simple command.
9352 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009353static int
9354isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009355{
9356 const char *q = endofname(p);
9357 if (p == q)
9358 return 0;
9359 return *q == '=';
9360}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009361static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009362bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009363{
9364 /* Preserve exitstatus of a previous possible redirection
9365 * as POSIX mandates */
9366 return back_exitstatus;
9367}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009368static int
Eric Andersenc470f442003-07-28 09:56:35 +00009369evalcommand(union node *cmd, int flags)
9370{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009371 static const struct builtincmd null_bltin = {
9372 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009373 };
Eric Andersenc470f442003-07-28 09:56:35 +00009374 struct stackmark smark;
9375 union node *argp;
9376 struct arglist arglist;
9377 struct arglist varlist;
9378 char **argv;
9379 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009380 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009381 struct cmdentry cmdentry;
9382 struct job *jp;
9383 char *lastarg;
9384 const char *path;
9385 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009386 int status;
9387 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009388 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009389 smallint cmd_is_exec;
9390 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009391
9392 /* First expand the arguments. */
9393 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9394 setstackmark(&smark);
9395 back_exitstatus = 0;
9396
9397 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009398 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009399 varlist.lastp = &varlist.list;
9400 *varlist.lastp = NULL;
9401 arglist.lastp = &arglist.list;
9402 *arglist.lastp = NULL;
9403
9404 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009405 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009406 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9407 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9408 }
9409
Eric Andersenc470f442003-07-28 09:56:35 +00009410 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9411 struct strlist **spp;
9412
9413 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009414 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009415 expandarg(argp, &arglist, EXP_VARTILDE);
9416 else
9417 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9418
Eric Andersenc470f442003-07-28 09:56:35 +00009419 for (sp = *spp; sp; sp = sp->next)
9420 argc++;
9421 }
9422
Denys Vlasenko65a8b852016-10-26 22:29:11 +02009423 /* Reserve one extra spot at the front for shellexec. */
9424 nargv = stalloc(sizeof(char *) * (argc + 2));
9425 argv = ++nargv;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009426 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009427 TRACE(("evalcommand arg: %s\n", sp->text));
9428 *nargv++ = sp->text;
9429 }
9430 *nargv = NULL;
9431
9432 lastarg = NULL;
9433 if (iflag && funcnest == 0 && argc > 0)
9434 lastarg = nargv[-1];
9435
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009436 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009437 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009438 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009439
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009440 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009441 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9442 struct strlist **spp;
9443 char *p;
9444
9445 spp = varlist.lastp;
9446 expandarg(argp, &varlist, EXP_VARTILDE);
9447
9448 /*
9449 * Modify the command lookup path, if a PATH= assignment
9450 * is present
9451 */
9452 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009453 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009454 path = p;
9455 }
9456
9457 /* Print the command if xflag is set. */
9458 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009459 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009460 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009461
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009462 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009463 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009464 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009465 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009466 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009467 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009468 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009469 }
9470 sp = arglist.list;
9471 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009472 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009473 }
9474
9475 cmd_is_exec = 0;
9476 spclbltin = -1;
9477
9478 /* Now locate the command. */
9479 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009480 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009481#if ENABLE_ASH_CMDCMD
9482 const char *oldpath = path + 5;
9483#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009484 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009485 for (;;) {
9486 find_command(argv[0], &cmdentry, cmd_flag, path);
9487 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009488 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009489 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009490 goto bail;
9491 }
9492
9493 /* implement bltin and command here */
9494 if (cmdentry.cmdtype != CMDBUILTIN)
9495 break;
9496 if (spclbltin < 0)
9497 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9498 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009499 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009500#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009501 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009502 path = oldpath;
9503 nargv = parse_command_args(argv, &path);
9504 if (!nargv)
9505 break;
Denys Vlasenkocac4d002016-10-01 03:02:25 +02009506 /* It's "command [-p] PROG ARGS" (that is, no -Vv).
9507 * nargv => "PROG". path is updated if -p.
9508 */
Eric Andersenc470f442003-07-28 09:56:35 +00009509 argc -= nargv - argv;
9510 argv = nargv;
9511 cmd_flag |= DO_NOFUNC;
9512 } else
9513#endif
9514 break;
9515 }
9516 }
9517
9518 if (status) {
9519 /* We have a redirection error. */
9520 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009521 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009522 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009523 exitstatus = status;
9524 goto out;
9525 }
9526
9527 /* Execute the command. */
9528 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009529 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009530
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009531#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009532/* (1) BUG: if variables are set, we need to fork, or save/restore them
9533 * around run_nofork_applet() call.
9534 * (2) Should this check also be done in forkshell()?
9535 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9536 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009537 /* find_command() encodes applet_no as (-2 - applet_no) */
9538 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009539 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009540 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009541 /* run <applet>_main() */
Ron Yorston5ccb0e92016-10-20 12:24:02 +01009542 status = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009543 break;
9544 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009545#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009546 /* Can we avoid forking off? For example, very last command
9547 * in a script or a subshell does not need forking,
9548 * we can just exec it.
9549 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009550 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009551 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009552 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009553 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009554 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009555 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009556 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009557 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009558 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009559 break;
9560 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009561 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009562 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009563 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009564 }
9565 listsetvar(varlist.list, VEXPORT|VSTACK);
9566 shellexec(argv, path, cmdentry.u.index);
9567 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009568 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009569 case CMDBUILTIN:
9570 cmdenviron = varlist.list;
9571 if (cmdenviron) {
9572 struct strlist *list = cmdenviron;
9573 int i = VNOSET;
9574 if (spclbltin > 0 || argc == 0) {
9575 i = 0;
9576 if (cmd_is_exec && argc > 1)
9577 i = VEXPORT;
9578 }
9579 listsetvar(list, i);
9580 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009581 /* Tight loop with builtins only:
9582 * "while kill -0 $child; do true; done"
9583 * will never exit even if $child died, unless we do this
9584 * to reap the zombie and make kill detect that it's gone: */
9585 dowait(DOWAIT_NONBLOCK, NULL);
9586
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009587 if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
Eric Andersenc470f442003-07-28 09:56:35 +00009588 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009589 int i = exception_type;
Denys Vlasenko061a0902016-10-25 17:24:25 +02009590 if (i == EXEXIT)
Eric Andersenc470f442003-07-28 09:56:35 +00009591 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009592 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009593 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009594 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009595 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009596 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009597 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009598 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009599 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009600 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009601 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009602 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009603 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009604 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009605
9606 case CMDFUNCTION:
9607 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009608 /* See above for the rationale */
9609 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009610 if (evalfun(cmdentry.u.func, argc, argv, flags))
9611 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009612 readstatus:
9613 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009614 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009615 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009616
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009617 out:
Denys Vlasenkoeaf94362016-10-25 21:46:03 +02009618 if (cmd->ncmd.redirect)
9619 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009620 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009621 /* dsl: I think this is intended to be used to support
9622 * '_' in 'vi' command mode during line editing...
9623 * However I implemented that within libedit itself.
9624 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009625 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009626 }
Eric Andersenc470f442003-07-28 09:56:35 +00009627 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009628
9629 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009630}
9631
9632static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009633evalbltin(const struct builtincmd *cmd, int argc, char **argv, int flags)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009634{
Eric Andersenc470f442003-07-28 09:56:35 +00009635 char *volatile savecmdname;
9636 struct jmploc *volatile savehandler;
9637 struct jmploc jmploc;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009638 int status;
Eric Andersenc470f442003-07-28 09:56:35 +00009639 int i;
9640
9641 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009642 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009643 i = setjmp(jmploc.loc);
9644 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009645 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009646 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009647 commandname = argv[0];
9648 argptr = argv + 1;
9649 optptr = NULL; /* initialize nextopt */
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009650 if (cmd == EVALCMD)
9651 status = evalcmd(argc, argv, flags);
9652 else
9653 status = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009654 flush_stdout_stderr();
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +02009655 status |= ferror(stdout);
9656 exitstatus = status;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009657 cmddone:
Rob Landleyf296f0b2006-07-06 01:09:21 +00009658 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009659 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009660 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009661
9662 return i;
9663}
9664
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009665static int
9666goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009667{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009668 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009669}
9670
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009671
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009672/*
9673 * Search for a command. This is called before we fork so that the
9674 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009675 * the child. The check for "goodname" is an overly conservative
9676 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009677 */
Eric Andersenc470f442003-07-28 09:56:35 +00009678static void
9679prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009680{
9681 struct cmdentry entry;
9682
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009683 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9684 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009685}
9686
Eric Andersencb57d552001-06-28 07:25:16 +00009687
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009688/* ============ Builtin commands
9689 *
9690 * Builtin commands whose functions are closely tied to evaluation
9691 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009692 */
9693
9694/*
Eric Andersencb57d552001-06-28 07:25:16 +00009695 * Handle break and continue commands. Break, continue, and return are
9696 * all handled by setting the evalskip flag. The evaluation routines
9697 * above all check this flag, and if it is set they start skipping
9698 * commands rather than executing them. The variable skipcount is
9699 * the number of loops to break/continue, or the number of function
9700 * levels to return. (The latter is always 1.) It should probably
9701 * be an error to break out of more loops than exist, but it isn't
9702 * in the standard shell so we don't make it one here.
9703 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009704static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009705breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009706{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009707 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009708
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009709 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009710 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009711 if (n > loopnest)
9712 n = loopnest;
9713 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009714 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009715 skipcount = n;
9716 }
9717 return 0;
9718}
9719
Eric Andersenc470f442003-07-28 09:56:35 +00009720
Denys Vlasenko70392332016-10-27 02:31:55 +02009721/*
Eric Andersen90898442003-08-06 11:20:52 +00009722 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009723 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009724
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009725enum {
9726 INPUT_PUSH_FILE = 1,
9727 INPUT_NOFILE_OK = 2,
9728};
Eric Andersencb57d552001-06-28 07:25:16 +00009729
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009730static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009731/* values of checkkwd variable */
9732#define CHKALIAS 0x1
9733#define CHKKWD 0x2
9734#define CHKNL 0x4
9735
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009736/*
9737 * Push a string back onto the input at this current parsefile level.
9738 * We handle aliases this way.
9739 */
9740#if !ENABLE_ASH_ALIAS
9741#define pushstring(s, ap) pushstring(s)
9742#endif
9743static void
9744pushstring(char *s, struct alias *ap)
9745{
9746 struct strpush *sp;
9747 int len;
9748
9749 len = strlen(s);
9750 INT_OFF;
9751 if (g_parsefile->strpush) {
9752 sp = ckzalloc(sizeof(*sp));
9753 sp->prev = g_parsefile->strpush;
9754 } else {
9755 sp = &(g_parsefile->basestrpush);
9756 }
9757 g_parsefile->strpush = sp;
9758 sp->prev_string = g_parsefile->next_to_pgetc;
9759 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009760 sp->unget = g_parsefile->unget;
9761 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009762#if ENABLE_ASH_ALIAS
9763 sp->ap = ap;
9764 if (ap) {
9765 ap->flag |= ALIASINUSE;
9766 sp->string = s;
9767 }
9768#endif
9769 g_parsefile->next_to_pgetc = s;
9770 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009771 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009772 INT_ON;
9773}
9774
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009775static void
9776popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009777{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009778 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009779
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009780 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009781#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009782 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009783 if (g_parsefile->next_to_pgetc[-1] == ' '
9784 || g_parsefile->next_to_pgetc[-1] == '\t'
9785 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009786 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009787 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009788 if (sp->string != sp->ap->val) {
9789 free(sp->string);
9790 }
9791 sp->ap->flag &= ~ALIASINUSE;
9792 if (sp->ap->flag & ALIASDEAD) {
9793 unalias(sp->ap->name);
9794 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009795 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009796#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009797 g_parsefile->next_to_pgetc = sp->prev_string;
9798 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009799 g_parsefile->unget = sp->unget;
9800 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009801 g_parsefile->strpush = sp->prev;
9802 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009803 free(sp);
9804 INT_ON;
9805}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009806
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009807static int
9808preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009809{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009810 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009811 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009812
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009813 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009814#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009815 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009816 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009817 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009818 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009819 int timeout = -1;
9820# if ENABLE_ASH_IDLE_TIMEOUT
9821 if (iflag) {
9822 const char *tmout_var = lookupvar("TMOUT");
9823 if (tmout_var) {
9824 timeout = atoi(tmout_var) * 1000;
9825 if (timeout <= 0)
9826 timeout = -1;
9827 }
9828 }
9829# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009830# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009831 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009832# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009833 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009834 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009835 if (nr == 0) {
9836 /* Ctrl+C pressed */
9837 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009838 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009839 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009840 raise(SIGINT);
9841 return 1;
9842 }
Eric Andersenc470f442003-07-28 09:56:35 +00009843 goto retry;
9844 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009845 if (nr < 0) {
9846 if (errno == 0) {
9847 /* Ctrl+D pressed */
9848 nr = 0;
9849 }
9850# if ENABLE_ASH_IDLE_TIMEOUT
9851 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009852 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009853 exitshell();
9854 }
9855# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009856 }
Eric Andersencb57d552001-06-28 07:25:16 +00009857 }
9858#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009859 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009860#endif
9861
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009862#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009863 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009864 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009865 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009866 if (flags >= 0 && (flags & O_NONBLOCK)) {
9867 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009868 if (fcntl(0, F_SETFL, flags) >= 0) {
9869 out2str("sh: turning off NDELAY mode\n");
9870 goto retry;
9871 }
9872 }
9873 }
9874 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009875#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009876 return nr;
9877}
9878
9879/*
9880 * Refill the input buffer and return the next input character:
9881 *
9882 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009883 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9884 * or we are reading from a string so we can't refill the buffer,
9885 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009886 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009887 * 4) Process input up to the next newline, deleting nul characters.
9888 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009889//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9890#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009891static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009892static int
Eric Andersenc470f442003-07-28 09:56:35 +00009893preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009894{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009895 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009896 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009897
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009898 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009899#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009900 if (g_parsefile->left_in_line == -1
9901 && g_parsefile->strpush->ap
9902 && g_parsefile->next_to_pgetc[-1] != ' '
9903 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009904 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009905 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009906 return PEOA;
9907 }
Eric Andersen2870d962001-07-02 17:27:21 +00009908#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009909 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009910 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009911 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009912 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009913 * "pgetc" needs refilling.
9914 */
9915
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009916 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009917 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009918 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009919 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009920 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009921 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009922 /* even in failure keep left_in_line and next_to_pgetc
9923 * in lock step, for correct multi-layer pungetc.
9924 * left_in_line was decremented before preadbuffer(),
9925 * must inc next_to_pgetc: */
9926 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009927 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009928 }
Eric Andersencb57d552001-06-28 07:25:16 +00009929
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009930 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009931 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009932 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009933 again:
9934 more = preadfd();
9935 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009936 /* don't try reading again */
9937 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009938 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009939 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009940 return PEOF;
9941 }
9942 }
9943
Denis Vlasenko727752d2008-11-28 03:41:47 +00009944 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009945 * Set g_parsefile->left_in_line
9946 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009947 * NUL chars are deleted.
9948 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009949 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009950 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009951 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009952
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009953 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009954
Denis Vlasenko727752d2008-11-28 03:41:47 +00009955 c = *q;
9956 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009957 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009958 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009959 q++;
9960 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009961 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009962 break;
9963 }
Eric Andersencb57d552001-06-28 07:25:16 +00009964 }
9965
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009966 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009967 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9968 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009969 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009970 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009971 }
9972 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009973 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009974
Eric Andersencb57d552001-06-28 07:25:16 +00009975 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009976 char save = *q;
9977 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009978 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009979 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009980 }
9981
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009982 pgetc_debug("preadbuffer at %d:%p'%s'",
9983 g_parsefile->left_in_line,
9984 g_parsefile->next_to_pgetc,
9985 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009986 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009987}
9988
Denys Vlasenkoce332a22016-10-02 23:47:34 +02009989static void
9990nlprompt(void)
9991{
9992 g_parsefile->linno++;
9993 setprompt_if(doprompt, 2);
9994}
9995static void
9996nlnoprompt(void)
9997{
9998 g_parsefile->linno++;
9999 needprompt = doprompt;
10000}
10001
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010002static int
10003pgetc(void)
10004{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010005 int c;
10006
10007 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010008 g_parsefile->left_in_line,
10009 g_parsefile->next_to_pgetc,
10010 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010011 if (g_parsefile->unget)
10012 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010013
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010014 if (--g_parsefile->left_in_line >= 0)
10015 c = (signed char)*g_parsefile->next_to_pgetc++;
10016 else
10017 c = preadbuffer();
10018
10019 g_parsefile->lastc[1] = g_parsefile->lastc[0];
10020 g_parsefile->lastc[0] = c;
10021
10022 return c;
10023}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010024
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010025#if ENABLE_ASH_ALIAS
10026static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010027pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010028{
10029 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010030 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010031 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010032 g_parsefile->left_in_line,
10033 g_parsefile->next_to_pgetc,
10034 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010035 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010036 } while (c == PEOA);
10037 return c;
10038}
10039#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010040# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010041#endif
10042
10043/*
10044 * Read a line from the script.
10045 */
10046static char *
10047pfgets(char *line, int len)
10048{
10049 char *p = line;
10050 int nleft = len;
10051 int c;
10052
10053 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010054 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010055 if (c == PEOF) {
10056 if (p == line)
10057 return NULL;
10058 break;
10059 }
10060 *p++ = c;
10061 if (c == '\n')
10062 break;
10063 }
10064 *p = '\0';
10065 return line;
10066}
10067
Eric Andersenc470f442003-07-28 09:56:35 +000010068/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010069 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010070 * PEOF may be pushed back.
10071 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010072static void
Eric Andersenc470f442003-07-28 09:56:35 +000010073pungetc(void)
10074{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010075 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010076}
10077
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010078/* This one eats backslash+newline */
10079static int
10080pgetc_eatbnl(void)
10081{
10082 int c;
10083
10084 while ((c = pgetc()) == '\\') {
10085 if (pgetc() != '\n') {
10086 pungetc();
10087 break;
10088 }
10089
Denys Vlasenkoce332a22016-10-02 23:47:34 +020010090 nlprompt();
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010091 }
10092
10093 return c;
10094}
10095
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010096/*
10097 * To handle the "." command, a stack of input files is used. Pushfile
10098 * adds a new entry to the stack and popfile restores the previous level.
10099 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010100static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010101pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010102{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010103 struct parsefile *pf;
10104
Denis Vlasenko597906c2008-02-20 16:38:54 +000010105 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010106 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010107 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010108 /*pf->strpush = NULL; - ckzalloc did it */
10109 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010110 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010111 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010112}
10113
10114static void
10115popfile(void)
10116{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010117 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010118
Denis Vlasenkob012b102007-02-19 22:43:01 +000010119 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010120 if (pf->pf_fd >= 0)
10121 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010122 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010123 while (pf->strpush)
10124 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010125 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010126 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010127 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010128}
10129
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010130/*
10131 * Return to top level.
10132 */
10133static void
10134popallfiles(void)
10135{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010136 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010137 popfile();
10138}
10139
10140/*
10141 * Close the file(s) that the shell is reading commands from. Called
10142 * after a fork is done.
10143 */
10144static void
10145closescript(void)
10146{
10147 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010148 if (g_parsefile->pf_fd > 0) {
10149 close(g_parsefile->pf_fd);
10150 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010151 }
10152}
10153
10154/*
10155 * Like setinputfile, but takes an open file descriptor. Call this with
10156 * interrupts off.
10157 */
10158static void
10159setinputfd(int fd, int push)
10160{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010161 if (push) {
10162 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010163 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010164 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010165 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010166 if (g_parsefile->buf == NULL)
10167 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010168 g_parsefile->left_in_buffer = 0;
10169 g_parsefile->left_in_line = 0;
10170 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010171}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010172
Eric Andersenc470f442003-07-28 09:56:35 +000010173/*
10174 * Set the input to take input from a file. If push is set, push the
10175 * old input onto the stack first.
10176 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010177static int
10178setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010179{
10180 int fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010181
Denis Vlasenkob012b102007-02-19 22:43:01 +000010182 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010183 fd = open(fname, O_RDONLY);
10184 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010185 if (flags & INPUT_NOFILE_OK)
10186 goto out;
Denys Vlasenkob7adf7a2016-10-25 17:00:13 +020010187 exitstatus = 127;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010188 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010189 }
Denys Vlasenko64774602016-10-26 15:24:30 +020010190 if (fd < 10)
10191 fd = savefd(fd);
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020010192 else
10193 close_on_exec_on(fd);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010194 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010195 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010196 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010197 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010198}
10199
Eric Andersencb57d552001-06-28 07:25:16 +000010200/*
10201 * Like setinputfile, but takes input from a string.
10202 */
Eric Andersenc470f442003-07-28 09:56:35 +000010203static void
10204setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010205{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010206 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010207 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010208 g_parsefile->next_to_pgetc = string;
10209 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010210 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010211 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010212 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010213}
10214
10215
Denys Vlasenko70392332016-10-27 02:31:55 +020010216/*
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010217 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010218 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010219
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010220#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010221
Denys Vlasenko23841622015-10-09 15:52:03 +020010222/* Hash of mtimes of mailboxes */
10223static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010224/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010225static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010226
Eric Andersencb57d552001-06-28 07:25:16 +000010227/*
Eric Andersenc470f442003-07-28 09:56:35 +000010228 * Print appropriate message(s) if mail has arrived.
10229 * If mail_var_path_changed is set,
10230 * then the value of MAIL has mail_var_path_changed,
10231 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010232 */
Eric Andersenc470f442003-07-28 09:56:35 +000010233static void
10234chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010235{
Eric Andersencb57d552001-06-28 07:25:16 +000010236 const char *mpath;
10237 char *p;
10238 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010239 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010240 struct stackmark smark;
10241 struct stat statb;
10242
Eric Andersencb57d552001-06-28 07:25:16 +000010243 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010244 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010245 new_hash = 0;
10246 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010247 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010248 if (p == NULL)
10249 break;
10250 if (*p == '\0')
10251 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010252 for (q = p; *q; q++)
10253 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010254#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010255 if (q[-1] != '/')
10256 abort();
10257#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010258 q[-1] = '\0'; /* delete trailing '/' */
10259 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010260 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010261 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010262 /* Very simplistic "hash": just a sum of all mtimes */
10263 new_hash += (unsigned)statb.st_mtime;
10264 }
10265 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010266 if (mailtime_hash != 0)
10267 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010268 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010269 }
Eric Andersenc470f442003-07-28 09:56:35 +000010270 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010271 popstackmark(&smark);
10272}
Eric Andersencb57d552001-06-28 07:25:16 +000010273
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010274static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010275changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010276{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010277 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010278}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010279
Denis Vlasenko131ae172007-02-18 13:00:19 +000010280#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010281
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010282
10283/* ============ ??? */
10284
Eric Andersencb57d552001-06-28 07:25:16 +000010285/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010286 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010287 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010288static void
10289setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010290{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010291 char **newparam;
10292 char **ap;
10293 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010294
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010295 for (nparam = 0; argv[nparam]; nparam++)
10296 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010297 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10298 while (*argv) {
10299 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010300 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010301 *ap = NULL;
10302 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010303 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010304 shellparam.nparam = nparam;
10305 shellparam.p = newparam;
10306#if ENABLE_ASH_GETOPTS
10307 shellparam.optind = 1;
10308 shellparam.optoff = -1;
10309#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010310}
10311
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010312/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010313 * Process shell options. The global variable argptr contains a pointer
10314 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010315 *
10316 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10317 * For a non-interactive shell, an error condition encountered
10318 * by a special built-in ... shall cause the shell to write a diagnostic message
10319 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010320 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010321 * ...
10322 * Utility syntax error (option or operand error) Shall exit
10323 * ...
10324 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10325 * we see that bash does not do that (set "finishes" with error code 1 instead,
10326 * and shell continues), and people rely on this behavior!
10327 * Testcase:
10328 * set -o barfoo 2>/dev/null
10329 * echo $?
10330 *
10331 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010332 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010333static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010334plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010335{
10336 int i;
10337
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010338 if (name) {
10339 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010340 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010341 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010342 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010343 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010344 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010345 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010346 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010347 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010348 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010349 if (val) {
10350 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10351 } else {
10352 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10353 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010354 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010355 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010356}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010357static void
10358setoption(int flag, int val)
10359{
10360 int i;
10361
10362 for (i = 0; i < NOPTS; i++) {
10363 if (optletters(i) == flag) {
10364 optlist[i] = val;
10365 return;
10366 }
10367 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010368 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010369 /* NOTREACHED */
10370}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010371static int
Eric Andersenc470f442003-07-28 09:56:35 +000010372options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010373{
10374 char *p;
10375 int val;
10376 int c;
10377
10378 if (cmdline)
10379 minusc = NULL;
10380 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010381 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010382 if (c != '-' && c != '+')
10383 break;
10384 argptr++;
10385 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010386 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010387 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010388 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010389 if (!cmdline) {
10390 /* "-" means turn off -x and -v */
10391 if (p[0] == '\0')
10392 xflag = vflag = 0;
10393 /* "--" means reset params */
10394 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010395 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010396 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010397 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010398 }
Eric Andersencb57d552001-06-28 07:25:16 +000010399 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010400 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010401 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010402 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010403 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010404 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010405 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010406 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010407 /* it already printed err message */
10408 return 1; /* error */
10409 }
Eric Andersencb57d552001-06-28 07:25:16 +000010410 if (*argptr)
10411 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010412 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10413 isloginsh = 1;
10414 /* bash does not accept +-login, we also won't */
10415 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010416 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010417 isloginsh = 1;
10418 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010419 } else {
10420 setoption(c, val);
10421 }
10422 }
10423 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010424 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010425}
10426
Eric Andersencb57d552001-06-28 07:25:16 +000010427/*
Eric Andersencb57d552001-06-28 07:25:16 +000010428 * The shift builtin command.
10429 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010430static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010431shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010432{
10433 int n;
10434 char **ap1, **ap2;
10435
10436 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010437 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010438 n = number(argv[1]);
10439 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010440 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010441 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010442 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010443 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010444 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010445 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010446 }
10447 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010448 while ((*ap2++ = *ap1++) != NULL)
10449 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010450#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010451 shellparam.optind = 1;
10452 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010453#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010454 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010455 return 0;
10456}
10457
Eric Andersencb57d552001-06-28 07:25:16 +000010458/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010459 * POSIX requires that 'set' (but not export or readonly) output the
10460 * variables in lexicographic order - by the locale's collating order (sigh).
10461 * Maybe we could keep them in an ordered balanced binary tree
10462 * instead of hashed lists.
10463 * For now just roll 'em through qsort for printing...
10464 */
10465static int
10466showvars(const char *sep_prefix, int on, int off)
10467{
10468 const char *sep;
10469 char **ep, **epend;
10470
10471 ep = listvars(on, off, &epend);
10472 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10473
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010474 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010475
10476 for (; ep < epend; ep++) {
10477 const char *p;
10478 const char *q;
10479
10480 p = strchrnul(*ep, '=');
10481 q = nullstr;
10482 if (*p)
10483 q = single_quote(++p);
10484 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10485 }
10486 return 0;
10487}
10488
10489/*
Eric Andersencb57d552001-06-28 07:25:16 +000010490 * The set command builtin.
10491 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010492static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010493setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010494{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010495 int retval;
10496
Denis Vlasenko68404f12008-03-17 09:00:54 +000010497 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010498 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010499
Denis Vlasenkob012b102007-02-19 22:43:01 +000010500 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010501 retval = options(/*cmdline:*/ 0);
10502 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010503 optschanged();
10504 if (*argptr != NULL) {
10505 setparam(argptr);
10506 }
Eric Andersencb57d552001-06-28 07:25:16 +000010507 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010508 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010509 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010510}
10511
Denis Vlasenko131ae172007-02-18 13:00:19 +000010512#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010513static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010514change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010515{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010516 uint32_t t;
10517
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010518 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010519 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010520 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010521 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010522 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010523 vrandom.flags &= ~VNOFUNC;
10524 } else {
10525 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010526 t = strtoul(value, NULL, 10);
10527 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010528 }
Eric Andersenef02f822004-03-11 13:34:24 +000010529}
Eric Andersen16767e22004-03-16 05:14:10 +000010530#endif
10531
Denis Vlasenko131ae172007-02-18 13:00:19 +000010532#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010533static int
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010534getopts(char *optstr, char *optvar, char **optfirst)
Eric Andersencb57d552001-06-28 07:25:16 +000010535{
10536 char *p, *q;
10537 char c = '?';
10538 int done = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010539 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010540 char **optnext;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010541 int ind = shellparam.optind;
10542 int off = shellparam.optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010543
Denys Vlasenko9c541002015-10-07 15:44:36 +020010544 sbuf[1] = '\0';
10545
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010546 shellparam.optind = -1;
10547 optnext = optfirst + ind - 1;
Eric Andersena48b0a32003-10-22 10:56:47 +000010548
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010549 if (ind <= 1 || off < 0 || (int)strlen(optnext[-1]) < off)
Eric Andersencb57d552001-06-28 07:25:16 +000010550 p = NULL;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010551 else
10552 p = optnext[-1] + off;
Eric Andersencb57d552001-06-28 07:25:16 +000010553 if (p == NULL || *p == '\0') {
10554 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010555 p = *optnext;
10556 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010557 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010558 p = NULL;
10559 done = 1;
10560 goto out;
10561 }
10562 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010563 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010564 goto atend;
10565 }
10566
10567 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010568 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010569 if (*q == '\0') {
10570 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010571 sbuf[0] = c;
10572 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010573 setvar0("OPTARG", sbuf);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010574 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010575 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010576 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010577 }
10578 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010579 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010580 }
10581 if (*++q == ':')
10582 q++;
10583 }
10584
10585 if (*++q == ':') {
10586 if (*p == '\0' && (p = *optnext) == NULL) {
10587 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010588 sbuf[0] = c;
10589 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010590 setvar0("OPTARG", sbuf);
Eric Andersencb57d552001-06-28 07:25:16 +000010591 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010592 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010593 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010594 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010595 c = '?';
10596 }
Eric Andersenc470f442003-07-28 09:56:35 +000010597 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010598 }
10599
10600 if (p == *optnext)
10601 optnext++;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010602 setvar0("OPTARG", p);
Eric Andersencb57d552001-06-28 07:25:16 +000010603 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010604 } else
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010605 setvar0("OPTARG", nullstr);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010606 out:
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010607 ind = optnext - optfirst + 1;
10608 setvar("OPTIND", itoa(ind), VNOFUNC);
Denys Vlasenko9c541002015-10-07 15:44:36 +020010609 sbuf[0] = c;
10610 /*sbuf[1] = '\0'; - already is */
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010611 setvar0(optvar, sbuf);
10612
10613 shellparam.optoff = p ? p - *(optnext - 1) : -1;
10614 shellparam.optind = ind;
10615
Eric Andersencb57d552001-06-28 07:25:16 +000010616 return done;
10617}
Eric Andersenc470f442003-07-28 09:56:35 +000010618
10619/*
10620 * The getopts builtin. Shellparam.optnext points to the next argument
10621 * to be processed. Shellparam.optptr points to the next character to
10622 * be processed in the current argument. If shellparam.optnext is NULL,
10623 * then it's the first time getopts has been called.
10624 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010625static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010626getoptscmd(int argc, char **argv)
10627{
10628 char **optbase;
10629
10630 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010631 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010632 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010633 optbase = shellparam.p;
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010634 if ((unsigned)shellparam.optind > shellparam.nparam + 1) {
Eric Andersenc470f442003-07-28 09:56:35 +000010635 shellparam.optind = 1;
10636 shellparam.optoff = -1;
10637 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010638 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010639 optbase = &argv[3];
Denys Vlasenkodbef38a2016-10-26 17:54:32 +020010640 if ((unsigned)shellparam.optind > argc - 2) {
Eric Andersenc470f442003-07-28 09:56:35 +000010641 shellparam.optind = 1;
10642 shellparam.optoff = -1;
10643 }
10644 }
10645
Denys Vlasenko35c2a132016-10-26 17:34:26 +020010646 return getopts(argv[1], argv[2], optbase);
Eric Andersenc470f442003-07-28 09:56:35 +000010647}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010648#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010649
Eric Andersencb57d552001-06-28 07:25:16 +000010650
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010651/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010652
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010653struct heredoc {
10654 struct heredoc *next; /* next here document in list */
10655 union node *here; /* redirection node */
10656 char *eofmark; /* string indicating end of input */
10657 smallint striptabs; /* if set, strip leading tabs */
10658};
10659
10660static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010661static smallint quoteflag; /* set if (part of) last token was quoted */
10662static token_id_t lasttoken; /* last token read (integer id Txxx) */
10663static struct heredoc *heredoclist; /* list of here documents to read */
10664static char *wordtext; /* text of last word returned by readtoken */
10665static struct nodelist *backquotelist;
10666static union node *redirnode;
10667static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010668
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010669static const char *
10670tokname(char *buf, int tok)
10671{
10672 if (tok < TSEMI)
Denys Vlasenko888527c2016-10-02 16:54:17 +020010673 return tokname_array[tok];
10674 sprintf(buf, "\"%s\"", tokname_array[tok]);
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010675 return buf;
10676}
10677
10678/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010679 * Called when an unexpected token is read during the parse. The argument
10680 * is the token that is expected, or -1 if more than one type of token can
10681 * occur at this point.
10682 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010683static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010684static void
10685raise_error_unexpected_syntax(int token)
10686{
10687 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010688 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010689 int l;
10690
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010691 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010692 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010693 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010694 raise_error_syntax(msg);
10695 /* NOTREACHED */
10696}
Eric Andersencb57d552001-06-28 07:25:16 +000010697
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010698#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010699
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010700/* parsing is heavily cross-recursive, need these forward decls */
10701static union node *andor(void);
10702static union node *pipeline(void);
10703static union node *parse_command(void);
10704static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010705static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010706static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010707
Eric Andersenc470f442003-07-28 09:56:35 +000010708static union node *
10709list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010710{
10711 union node *n1, *n2, *n3;
10712 int tok;
10713
Eric Andersencb57d552001-06-28 07:25:16 +000010714 n1 = NULL;
10715 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010716 switch (peektoken()) {
10717 case TNL:
10718 if (!(nlflag & 1))
10719 break;
10720 parseheredoc();
10721 return n1;
10722
10723 case TEOF:
10724 if (!n1 && (nlflag & 1))
10725 n1 = NODE_EOF;
10726 parseheredoc();
10727 return n1;
10728 }
10729
10730 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko888527c2016-10-02 16:54:17 +020010731 if (nlflag == 2 && ((1 << peektoken()) & tokendlist))
Ron Yorstonc0e00762015-10-29 11:30:55 +000010732 return n1;
10733 nlflag |= 2;
10734
Eric Andersencb57d552001-06-28 07:25:16 +000010735 n2 = andor();
10736 tok = readtoken();
10737 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010738 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010739 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010740 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010741 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010742 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010743 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010744 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010745 n2 = n3;
10746 }
10747 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010748 }
10749 }
10750 if (n1 == NULL) {
10751 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010752 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010753 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010754 n3->type = NSEMI;
10755 n3->nbinary.ch1 = n1;
10756 n3->nbinary.ch2 = n2;
10757 n1 = n3;
10758 }
10759 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010760 case TNL:
10761 case TEOF:
10762 tokpushback = 1;
10763 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010764 case TBACKGND:
10765 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010766 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010767 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010768 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010769 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010770 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010771 return n1;
10772 }
10773 }
10774}
10775
Eric Andersenc470f442003-07-28 09:56:35 +000010776static union node *
10777andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010778{
Eric Andersencb57d552001-06-28 07:25:16 +000010779 union node *n1, *n2, *n3;
10780 int t;
10781
Eric Andersencb57d552001-06-28 07:25:16 +000010782 n1 = pipeline();
10783 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010784 t = readtoken();
10785 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010786 t = NAND;
10787 } else if (t == TOR) {
10788 t = NOR;
10789 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010790 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010791 return n1;
10792 }
Eric Andersenc470f442003-07-28 09:56:35 +000010793 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010794 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010795 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010796 n3->type = t;
10797 n3->nbinary.ch1 = n1;
10798 n3->nbinary.ch2 = n2;
10799 n1 = n3;
10800 }
10801}
10802
Eric Andersenc470f442003-07-28 09:56:35 +000010803static union node *
10804pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010805{
Eric Andersencb57d552001-06-28 07:25:16 +000010806 union node *n1, *n2, *pipenode;
10807 struct nodelist *lp, *prev;
10808 int negate;
10809
10810 negate = 0;
10811 TRACE(("pipeline: entered\n"));
10812 if (readtoken() == TNOT) {
10813 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010814 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010815 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010816 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010817 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010818 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010819 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010820 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010821 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010822 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010823 pipenode->npipe.cmdlist = lp;
10824 lp->n = n1;
10825 do {
10826 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010827 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010828 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010829 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010830 prev->next = lp;
10831 } while (readtoken() == TPIPE);
10832 lp->next = NULL;
10833 n1 = pipenode;
10834 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010835 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010836 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010837 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010838 n2->type = NNOT;
10839 n2->nnot.com = n1;
10840 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010841 }
10842 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010843}
10844
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010845static union node *
10846makename(void)
10847{
10848 union node *n;
10849
Denis Vlasenko597906c2008-02-20 16:38:54 +000010850 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010851 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010852 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010853 n->narg.text = wordtext;
10854 n->narg.backquote = backquotelist;
10855 return n;
10856}
10857
10858static void
10859fixredir(union node *n, const char *text, int err)
10860{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010861 int fd;
10862
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010863 TRACE(("Fix redir %s %d\n", text, err));
10864 if (!err)
10865 n->ndup.vname = NULL;
10866
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010867 fd = bb_strtou(text, NULL, 10);
10868 if (!errno && fd >= 0)
10869 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010870 else if (LONE_DASH(text))
10871 n->ndup.dupfd = -1;
10872 else {
10873 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010874 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010875 n->ndup.vname = makename();
10876 }
10877}
10878
10879/*
10880 * Returns true if the text contains nothing to expand (no dollar signs
10881 * or backquotes).
10882 */
10883static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010884noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010885{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010886 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010887
Denys Vlasenkocd716832009-11-28 22:14:02 +010010888 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010889 if (c == CTLQUOTEMARK)
10890 continue;
10891 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010892 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010893 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010894 return 0;
10895 }
10896 return 1;
10897}
10898
10899static void
10900parsefname(void)
10901{
10902 union node *n = redirnode;
10903
10904 if (readtoken() != TWORD)
10905 raise_error_unexpected_syntax(-1);
10906 if (n->type == NHERE) {
10907 struct heredoc *here = heredoc;
10908 struct heredoc *p;
10909 int i;
10910
10911 if (quoteflag == 0)
10912 n->type = NXHERE;
10913 TRACE(("Here document %d\n", n->type));
10914 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010915 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010916 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010917 here->eofmark = wordtext;
10918 here->next = NULL;
10919 if (heredoclist == NULL)
10920 heredoclist = here;
10921 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010922 for (p = heredoclist; p->next; p = p->next)
10923 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010924 p->next = here;
10925 }
10926 } else if (n->type == NTOFD || n->type == NFROMFD) {
10927 fixredir(n, wordtext, 0);
10928 } else {
10929 n->nfile.fname = makename();
10930 }
10931}
Eric Andersencb57d552001-06-28 07:25:16 +000010932
Eric Andersenc470f442003-07-28 09:56:35 +000010933static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010934simplecmd(void)
10935{
10936 union node *args, **app;
10937 union node *n = NULL;
10938 union node *vars, **vpp;
10939 union node **rpp, *redir;
10940 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010941#if ENABLE_ASH_BASH_COMPAT
10942 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000010943 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010944#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010945
10946 args = NULL;
10947 app = &args;
10948 vars = NULL;
10949 vpp = &vars;
10950 redir = NULL;
10951 rpp = &redir;
10952
10953 savecheckkwd = CHKALIAS;
10954 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010955 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010956 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010957 t = readtoken();
10958 switch (t) {
10959#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000010960 case TFUNCTION:
10961 if (peektoken() != TWORD)
10962 raise_error_unexpected_syntax(TWORD);
10963 function_flag = 1;
10964 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010965 case TAND: /* "&&" */
10966 case TOR: /* "||" */
10967 if (!double_brackets_flag) {
10968 tokpushback = 1;
10969 goto out;
10970 }
10971 wordtext = (char *) (t == TAND ? "-a" : "-o");
10972#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010973 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010974 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010975 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010976 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010977 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010978#if ENABLE_ASH_BASH_COMPAT
10979 if (strcmp("[[", wordtext) == 0)
10980 double_brackets_flag = 1;
10981 else if (strcmp("]]", wordtext) == 0)
10982 double_brackets_flag = 0;
10983#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010984 n->narg.backquote = backquotelist;
10985 if (savecheckkwd && isassignment(wordtext)) {
10986 *vpp = n;
10987 vpp = &n->narg.next;
10988 } else {
10989 *app = n;
10990 app = &n->narg.next;
10991 savecheckkwd = 0;
10992 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000010993#if ENABLE_ASH_BASH_COMPAT
10994 if (function_flag) {
10995 checkkwd = CHKNL | CHKKWD;
10996 switch (peektoken()) {
10997 case TBEGIN:
10998 case TIF:
10999 case TCASE:
11000 case TUNTIL:
11001 case TWHILE:
11002 case TFOR:
11003 goto do_func;
11004 case TLP:
11005 function_flag = 0;
11006 break;
11007 case TWORD:
11008 if (strcmp("[[", wordtext) == 0)
11009 goto do_func;
11010 /* fall through */
11011 default:
11012 raise_error_unexpected_syntax(-1);
11013 }
11014 }
11015#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011016 break;
11017 case TREDIR:
11018 *rpp = n = redirnode;
11019 rpp = &n->nfile.next;
11020 parsefname(); /* read name of redirection file */
11021 break;
11022 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000011023 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011024 if (args && app == &args->narg.next
11025 && !vars && !redir
11026 ) {
11027 struct builtincmd *bcmd;
11028 const char *name;
11029
11030 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000011031 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011032 raise_error_unexpected_syntax(TRP);
11033 name = n->narg.text;
11034 if (!goodname(name)
11035 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
11036 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011037 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011038 }
11039 n->type = NDEFUN;
11040 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11041 n->narg.next = parse_command();
11042 return n;
11043 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000011044 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011045 /* fall through */
11046 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011047 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011048 goto out;
11049 }
11050 }
11051 out:
11052 *app = NULL;
11053 *vpp = NULL;
11054 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011055 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011056 n->type = NCMD;
11057 n->ncmd.args = args;
11058 n->ncmd.assign = vars;
11059 n->ncmd.redirect = redir;
11060 return n;
11061}
11062
11063static union node *
11064parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011065{
Eric Andersencb57d552001-06-28 07:25:16 +000011066 union node *n1, *n2;
11067 union node *ap, **app;
11068 union node *cp, **cpp;
11069 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011070 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011071 int t;
11072
11073 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011074 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011075
Eric Andersencb57d552001-06-28 07:25:16 +000011076 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011077 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011078 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011079 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011080 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011081 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011082 n1->type = NIF;
11083 n1->nif.test = list(0);
11084 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011085 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011086 n1->nif.ifpart = list(0);
11087 n2 = n1;
11088 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011089 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011090 n2 = n2->nif.elsepart;
11091 n2->type = NIF;
11092 n2->nif.test = list(0);
11093 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011094 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011095 n2->nif.ifpart = list(0);
11096 }
11097 if (lasttoken == TELSE)
11098 n2->nif.elsepart = list(0);
11099 else {
11100 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011101 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011102 }
Eric Andersenc470f442003-07-28 09:56:35 +000011103 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011104 break;
11105 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011106 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011107 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011108 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011109 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011110 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011111 got = readtoken();
11112 if (got != TDO) {
Denys Vlasenko888527c2016-10-02 16:54:17 +020011113 TRACE(("expecting DO got '%s' %s\n", tokname_array[got],
Denis Vlasenko131ae172007-02-18 13:00:19 +000011114 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011115 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011116 }
11117 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011118 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011119 break;
11120 }
11121 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011122 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011123 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011124 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011125 n1->type = NFOR;
11126 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011127 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011128 if (readtoken() == TIN) {
11129 app = &ap;
11130 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011131 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011132 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011133 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011134 n2->narg.text = wordtext;
11135 n2->narg.backquote = backquotelist;
11136 *app = n2;
11137 app = &n2->narg.next;
11138 }
11139 *app = NULL;
11140 n1->nfor.args = ap;
11141 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011142 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011143 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011144 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011145 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011146 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011147 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011148 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011149 n1->nfor.args = n2;
11150 /*
11151 * Newline or semicolon here is optional (but note
11152 * that the original Bourne shell only allowed NL).
11153 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011154 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011155 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011156 }
Eric Andersenc470f442003-07-28 09:56:35 +000011157 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011158 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011159 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011160 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011161 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011162 break;
11163 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011164 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011165 n1->type = NCASE;
11166 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011167 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011168 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011169 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011170 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011171 n2->narg.text = wordtext;
11172 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011173 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11174 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011175 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011176 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011177 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011178 checkkwd = CHKNL | CHKKWD;
11179 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011180 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011181 if (lasttoken == TLP)
11182 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011183 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011184 cp->type = NCLIST;
11185 app = &cp->nclist.pattern;
11186 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011187 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011188 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011189 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011190 ap->narg.text = wordtext;
11191 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011192 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011193 break;
11194 app = &ap->narg.next;
11195 readtoken();
11196 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011197 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011198 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011199 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011200 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011201
Eric Andersenc470f442003-07-28 09:56:35 +000011202 cpp = &cp->nclist.next;
11203
11204 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011205 t = readtoken();
11206 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011207 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011208 raise_error_unexpected_syntax(TENDCASE);
11209 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011210 }
Eric Andersenc470f442003-07-28 09:56:35 +000011211 }
Eric Andersencb57d552001-06-28 07:25:16 +000011212 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011213 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011214 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011215 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011216 n1->type = NSUBSHELL;
11217 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011218 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011219 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011220 break;
11221 case TBEGIN:
11222 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011223 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011224 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011225 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011226 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011227 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011228 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011229 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011230 }
11231
Eric Andersenc470f442003-07-28 09:56:35 +000011232 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011233 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011234
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011235 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011236 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011237 checkkwd = CHKKWD | CHKALIAS;
11238 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011239 while (readtoken() == TREDIR) {
11240 *rpp = n2 = redirnode;
11241 rpp = &n2->nfile.next;
11242 parsefname();
11243 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011244 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011245 *rpp = NULL;
11246 if (redir) {
11247 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011248 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011249 n2->type = NREDIR;
11250 n2->nredir.n = n1;
11251 n1 = n2;
11252 }
11253 n1->nredir.redirect = redir;
11254 }
Eric Andersencb57d552001-06-28 07:25:16 +000011255 return n1;
11256}
11257
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011258#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko37dc08b2016-10-02 04:38:07 +020011259static int
11260decode_dollar_squote(void)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011261{
11262 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11263 int c, cnt;
11264 char *p;
11265 char buf[4];
11266
11267 c = pgetc();
11268 p = strchr(C_escapes, c);
11269 if (p) {
11270 buf[0] = c;
11271 p = buf;
11272 cnt = 3;
11273 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11274 do {
11275 c = pgetc();
11276 *++p = c;
11277 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11278 pungetc();
11279 } else if (c == 'x') { /* \xHH */
11280 do {
11281 c = pgetc();
11282 *++p = c;
11283 } while (isxdigit(c) && --cnt);
11284 pungetc();
11285 if (cnt == 3) { /* \x but next char is "bad" */
11286 c = 'x';
11287 goto unrecognized;
11288 }
11289 } else { /* simple seq like \\ or \t */
11290 p++;
11291 }
11292 *p = '\0';
11293 p = buf;
11294 c = bb_process_escape_sequence((void*)&p);
11295 } else { /* unrecognized "\z": print both chars unless ' or " */
11296 if (c != '\'' && c != '"') {
11297 unrecognized:
11298 c |= 0x100; /* "please encode \, then me" */
11299 }
11300 }
11301 return c;
11302}
11303#endif
11304
Eric Andersencb57d552001-06-28 07:25:16 +000011305/*
11306 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11307 * is not NULL, read a here document. In the latter case, eofmark is the
11308 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011309 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011310 * is the first character of the input token or document.
11311 *
11312 * Because C does not have internal subroutines, I have simulated them
11313 * using goto's to implement the subroutine linkage. The following macros
11314 * will run code that appears at the end of readtoken1.
11315 */
Eric Andersen2870d962001-07-02 17:27:21 +000011316#define CHECKEND() {goto checkend; checkend_return:;}
11317#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11318#define PARSESUB() {goto parsesub; parsesub_return:;}
11319#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11320#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11321#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011322static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011323readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011324{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011325 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011326 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011327 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011328 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011329 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011330 struct nodelist *bqlist;
11331 smallint quotef;
11332 smallint dblquote;
11333 smallint oldstyle;
11334 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011335#if ENABLE_ASH_EXPAND_PRMT
11336 smallint pssyntax; /* we are expanding a prompt string */
11337#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011338 int varnest; /* levels of variables expansion */
11339 int arinest; /* levels of arithmetic expansion */
11340 int parenlevel; /* levels of parens in arithmetic */
11341 int dqvarnest; /* levels of variables expansion within double quotes */
11342
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011343 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011344
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011345 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011346 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011347 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011348 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011349#if ENABLE_ASH_EXPAND_PRMT
11350 pssyntax = (syntax == PSSYNTAX);
11351 if (pssyntax)
11352 syntax = DQSYNTAX;
11353#endif
11354 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011355 varnest = 0;
11356 arinest = 0;
11357 parenlevel = 0;
11358 dqvarnest = 0;
11359
11360 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011361 loop:
11362 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011363 CHECKEND(); /* set c to PEOF if at end of here document */
11364 for (;;) { /* until end of line or end of word */
11365 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11366 switch (SIT(c, syntax)) {
11367 case CNL: /* '\n' */
11368 if (syntax == BASESYNTAX)
11369 goto endword; /* exit outer loop */
11370 USTPUTC(c, out);
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011371 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011372 c = pgetc();
11373 goto loop; /* continue outer loop */
11374 case CWORD:
11375 USTPUTC(c, out);
11376 break;
11377 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011378#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011379 if (c == '\\' && bash_dollar_squote) {
11380 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011381 if (c == '\0') {
11382 /* skip $'\000', $'\x00' (like bash) */
11383 break;
11384 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011385 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011386 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011387 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011388 if (eofmark == NULL || dblquote)
11389 USTPUTC(CTLESC, out);
11390 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011391 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011392 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011393#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011394 if (eofmark == NULL || dblquote)
11395 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011396 USTPUTC(c, out);
11397 break;
11398 case CBACK: /* backslash */
11399 c = pgetc_without_PEOA();
11400 if (c == PEOF) {
11401 USTPUTC(CTLESC, out);
11402 USTPUTC('\\', out);
11403 pungetc();
11404 } else if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011405 nlprompt();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011406 } else {
11407#if ENABLE_ASH_EXPAND_PRMT
11408 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011409 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011410 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011411 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011412#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011413 /* Backslash is retained if we are in "str" and next char isn't special */
11414 if (dblquote
11415 && c != '\\'
11416 && c != '`'
11417 && c != '$'
11418 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011419 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011420 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011421 }
Ron Yorston549deab2015-05-18 09:57:51 +020011422 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011423 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011424 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011425 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011426 break;
11427 case CSQUOTE:
11428 syntax = SQSYNTAX;
11429 quotemark:
11430 if (eofmark == NULL) {
11431 USTPUTC(CTLQUOTEMARK, out);
11432 }
11433 break;
11434 case CDQUOTE:
11435 syntax = DQSYNTAX;
11436 dblquote = 1;
11437 goto quotemark;
11438 case CENDQUOTE:
11439 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011440 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011441 USTPUTC(c, out);
11442 } else {
11443 if (dqvarnest == 0) {
11444 syntax = BASESYNTAX;
11445 dblquote = 0;
11446 }
11447 quotef = 1;
11448 goto quotemark;
11449 }
11450 break;
11451 case CVAR: /* '$' */
11452 PARSESUB(); /* parse substitution */
11453 break;
11454 case CENDVAR: /* '}' */
11455 if (varnest > 0) {
11456 varnest--;
11457 if (dqvarnest > 0) {
11458 dqvarnest--;
11459 }
11460 c = CTLENDVAR;
11461 }
11462 USTPUTC(c, out);
11463 break;
11464#if ENABLE_SH_MATH_SUPPORT
11465 case CLP: /* '(' in arithmetic */
11466 parenlevel++;
11467 USTPUTC(c, out);
11468 break;
11469 case CRP: /* ')' in arithmetic */
11470 if (parenlevel > 0) {
11471 parenlevel--;
11472 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011473 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011474 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011475 if (--arinest == 0) {
11476 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011477 }
11478 } else {
11479 /*
11480 * unbalanced parens
11481 * (don't 2nd guess - no error)
11482 */
11483 pungetc();
11484 }
11485 }
11486 USTPUTC(c, out);
11487 break;
11488#endif
11489 case CBQUOTE: /* '`' */
11490 PARSEBACKQOLD();
11491 break;
11492 case CENDFILE:
11493 goto endword; /* exit outer loop */
11494 case CIGN:
11495 break;
11496 default:
11497 if (varnest == 0) {
11498#if ENABLE_ASH_BASH_COMPAT
11499 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011500//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011501 if (pgetc() == '>')
11502 c = 0x100 + '>'; /* flag &> */
11503 pungetc();
11504 }
11505#endif
11506 goto endword; /* exit outer loop */
11507 }
11508 IF_ASH_ALIAS(if (c != PEOA))
11509 USTPUTC(c, out);
11510 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011511 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011512 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011513 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011514
Mike Frysinger98c52642009-04-02 10:02:37 +000011515#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011516 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011517 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011518#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011519 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011520 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011521 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011522 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011523 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011524 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011525 }
11526 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011527 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011528 out = stackblock();
11529 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011530 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011531 && quotef == 0
11532 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011533 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011534 PARSEREDIR(); /* passed as params: out, c */
11535 lasttoken = TREDIR;
11536 return lasttoken;
11537 }
11538 /* else: non-number X seen, interpret it
11539 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011540 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011541 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011542 }
11543 quoteflag = quotef;
11544 backquotelist = bqlist;
11545 grabstackblock(len);
11546 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011547 lasttoken = TWORD;
11548 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011549/* end of readtoken routine */
11550
Eric Andersencb57d552001-06-28 07:25:16 +000011551/*
11552 * Check to see whether we are at the end of the here document. When this
11553 * is called, c is set to the first character of the next input line. If
11554 * we are at the end of the here document, this routine sets the c to PEOF.
11555 */
Eric Andersenc470f442003-07-28 09:56:35 +000011556checkend: {
11557 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011558#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011559 if (c == PEOA)
11560 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011561#endif
11562 if (striptabs) {
11563 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011564 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011565 }
Eric Andersenc470f442003-07-28 09:56:35 +000011566 }
11567 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011568 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011569 char *p, *q;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011570 int cc;
Eric Andersencb57d552001-06-28 07:25:16 +000011571
Eric Andersenc470f442003-07-28 09:56:35 +000011572 p = line;
Denys Vlasenko350e6862016-10-26 16:26:45 +020011573 for (q = eofmark + 1;; p++, q++) {
11574 cc = *p;
11575 if (cc == '\n')
11576 cc = 0;
11577 if (!*q || cc != *q)
11578 break;
11579 }
11580 if (cc == *q) {
Eric Andersenc470f442003-07-28 09:56:35 +000011581 c = PEOF;
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011582 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011583 } else {
11584 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011585 }
11586 }
11587 }
11588 }
Eric Andersenc470f442003-07-28 09:56:35 +000011589 goto checkend_return;
11590}
Eric Andersencb57d552001-06-28 07:25:16 +000011591
Eric Andersencb57d552001-06-28 07:25:16 +000011592/*
11593 * Parse a redirection operator. The variable "out" points to a string
11594 * specifying the fd to be redirected. The variable "c" contains the
11595 * first character of the redirection operator.
11596 */
Eric Andersenc470f442003-07-28 09:56:35 +000011597parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011598 /* out is already checked to be a valid number or "" */
11599 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011600 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011601
Denis Vlasenko597906c2008-02-20 16:38:54 +000011602 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011603 if (c == '>') {
11604 np->nfile.fd = 1;
11605 c = pgetc();
11606 if (c == '>')
11607 np->type = NAPPEND;
11608 else if (c == '|')
11609 np->type = NCLOBBER;
11610 else if (c == '&')
11611 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011612 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011613 else {
11614 np->type = NTO;
11615 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011616 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011617 }
11618#if ENABLE_ASH_BASH_COMPAT
11619 else if (c == 0x100 + '>') { /* this flags &> redirection */
11620 np->nfile.fd = 1;
11621 pgetc(); /* this is '>', no need to check */
11622 np->type = NTO2;
11623 }
11624#endif
11625 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011626 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011627 c = pgetc();
11628 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011629 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011630 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011631 np = stzalloc(sizeof(struct nhere));
11632 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011633 }
11634 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011635 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011636 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011637 c = pgetc();
11638 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011639 heredoc->striptabs = 1;
11640 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011641 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011642 pungetc();
11643 }
11644 break;
11645
11646 case '&':
11647 np->type = NFROMFD;
11648 break;
11649
11650 case '>':
11651 np->type = NFROMTO;
11652 break;
11653
11654 default:
11655 np->type = NFROM;
11656 pungetc();
11657 break;
11658 }
Eric Andersencb57d552001-06-28 07:25:16 +000011659 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011660 if (fd >= 0)
11661 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011662 redirnode = np;
11663 goto parseredir_return;
11664}
Eric Andersencb57d552001-06-28 07:25:16 +000011665
Eric Andersencb57d552001-06-28 07:25:16 +000011666/*
11667 * Parse a substitution. At this point, we have read the dollar sign
11668 * and nothing else.
11669 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011670
11671/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11672 * (assuming ascii char codes, as the original implementation did) */
11673#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011674 (((unsigned)(c) - 33 < 32) \
11675 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011676parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011677 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011678 int typeloc;
Eric Andersencb57d552001-06-28 07:25:16 +000011679
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011680 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011681 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011682 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011683 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011684#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011685 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011686 bash_dollar_squote = 1;
11687 else
11688#endif
11689 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011690 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011691 } else if (c == '(') {
11692 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011693 if (pgetc_eatbnl() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011694#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011695 PARSEARITH();
11696#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011697 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011698#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011699 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011700 pungetc();
11701 PARSEBACKQNEW();
11702 }
11703 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011704 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011705 USTPUTC(CTLVAR, out);
11706 typeloc = out - (char *)stackblock();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011707 STADJUST(1, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011708 subtype = VSNORMAL;
11709 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011710 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011711 subtype = 0;
Eric Andersenc470f442003-07-28 09:56:35 +000011712 }
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011713 varname:
Denys Vlasenko3df14102016-10-26 16:41:13 +020011714 if (is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011715 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011716 do {
11717 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011718 c = pgetc_eatbnl();
Denys Vlasenko3df14102016-10-26 16:41:13 +020011719 } while (is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011720 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011721 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011722 do {
11723 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011724 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011725 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011726 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011727 /* $[{[#]]<specialchar>[}] */
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011728 int cc = c;
11729
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011730 c = pgetc_eatbnl();
Denys Vlasenkof15aa572016-10-26 15:56:53 +020011731 if (!subtype && cc == '#') {
11732 subtype = VSLENGTH;
11733 if (c == '_' || isalnum(c))
11734 goto varname;
11735 cc = c;
11736 c = pgetc_eatbnl();
11737 if (cc == '}' || c != '}') {
11738 pungetc();
11739 subtype = 0;
11740 c = cc;
11741 cc = '#';
11742 }
11743 }
11744 USTPUTC(cc, out);
Denis Vlasenko559691a2008-10-05 18:39:31 +000011745 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011746 goto badsub;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011747 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011748 if (c != '}' && subtype == VSLENGTH) {
11749 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011750 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011751 }
Eric Andersencb57d552001-06-28 07:25:16 +000011752
Eric Andersenc470f442003-07-28 09:56:35 +000011753 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011754 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011755 /* ${VAR...} but not $VAR or ${#VAR} */
11756 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011757 switch (c) {
11758 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011759 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011760#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011761 /* This check is only needed to not misinterpret
11762 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11763 * constructs.
11764 */
11765 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011766 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011767 pungetc();
Denys Vlasenko88e15702016-10-26 01:55:56 +020011768 break; /* "goto badsub" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011769 }
11770#endif
Denys Vlasenko3df14102016-10-26 16:41:13 +020011771 subtype = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011772 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011773 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011774 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011775 if (p == NULL)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011776 break;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011777 subtype |= p - types + VSNORMAL;
Eric Andersenc470f442003-07-28 09:56:35 +000011778 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011779 }
Eric Andersenc470f442003-07-28 09:56:35 +000011780 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011781 case '#': {
11782 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011783 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011784 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011785 if (c != cc)
Denys Vlasenko88e15702016-10-26 01:55:56 +020011786 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011787 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011788 break;
11789 }
11790#if ENABLE_ASH_BASH_COMPAT
11791 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011792 /* ${v/[/]pattern/repl} */
11793//TODO: encode pattern and repl separately.
11794// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011795 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011796 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011797 if (c != '/')
Denys Vlasenko88e15702016-10-26 01:55:56 +020011798 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011799 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011800 break;
11801#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011802 }
Eric Andersenc470f442003-07-28 09:56:35 +000011803 } else {
Denys Vlasenko88e15702016-10-26 01:55:56 +020011804 badsub:
Eric Andersenc470f442003-07-28 09:56:35 +000011805 pungetc();
11806 }
Denys Vlasenko3df14102016-10-26 16:41:13 +020011807 ((unsigned char *)stackblock())[typeloc] = subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011808 if (subtype != VSNORMAL) {
11809 varnest++;
Denys Vlasenko3df14102016-10-26 16:41:13 +020011810 if (dblquote)
Eric Andersenc470f442003-07-28 09:56:35 +000011811 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011812 }
Denys Vlasenko88e15702016-10-26 01:55:56 +020011813 STPUTC('=', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011814 }
Eric Andersenc470f442003-07-28 09:56:35 +000011815 goto parsesub_return;
11816}
Eric Andersencb57d552001-06-28 07:25:16 +000011817
Eric Andersencb57d552001-06-28 07:25:16 +000011818/*
11819 * Called to parse command substitutions. Newstyle is set if the command
11820 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11821 * list of commands (passed by reference), and savelen is the number of
11822 * characters on the top of the stack which must be preserved.
11823 */
Eric Andersenc470f442003-07-28 09:56:35 +000011824parsebackq: {
11825 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011826 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011827 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011828 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011829 smallint saveprompt = 0;
11830
Eric Andersenc470f442003-07-28 09:56:35 +000011831 str = NULL;
11832 savelen = out - (char *)stackblock();
11833 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011834 /*
11835 * FIXME: this can allocate very large block on stack and SEGV.
11836 * Example:
11837 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011838 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011839 * a hundred command substitutions stack overflows.
11840 * With larger prepended string, SEGV happens sooner.
11841 */
Ron Yorston072fc602015-07-01 16:46:18 +010011842 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011843 memcpy(str, stackblock(), savelen);
11844 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011845
Eric Andersenc470f442003-07-28 09:56:35 +000011846 if (oldstyle) {
11847 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011848 * treatment to some slashes, and then push the string and
11849 * reread it as input, interpreting it normally.
11850 */
Eric Andersenc470f442003-07-28 09:56:35 +000011851 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011852 size_t psavelen;
11853 char *pstr;
11854
Eric Andersenc470f442003-07-28 09:56:35 +000011855 STARTSTACKSTR(pout);
11856 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011857 int pc;
11858
11859 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011860 pc = pgetc();
11861 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011862 case '`':
11863 goto done;
11864
11865 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011866 pc = pgetc();
11867 if (pc == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011868 nlprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011869 /*
11870 * If eating a newline, avoid putting
11871 * the newline into the new character
11872 * stream (via the STPUTC after the
11873 * switch).
11874 */
11875 continue;
11876 }
11877 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011878 && (!dblquote || pc != '"')
11879 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011880 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011881 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011882 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011883 break;
11884 }
11885 /* fall through */
11886
11887 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011888 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011889 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011890 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011891
11892 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020011893 nlnoprompt();
Eric Andersenc470f442003-07-28 09:56:35 +000011894 break;
11895
11896 default:
11897 break;
11898 }
11899 STPUTC(pc, pout);
11900 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011901 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011902 STPUTC('\0', pout);
11903 psavelen = pout - (char *)stackblock();
11904 if (psavelen > 0) {
11905 pstr = grabstackstr(pout);
11906 setinputstring(pstr);
11907 }
11908 }
11909 nlpp = &bqlist;
11910 while (*nlpp)
11911 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011912 *nlpp = stzalloc(sizeof(**nlpp));
11913 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011914
11915 if (oldstyle) {
11916 saveprompt = doprompt;
11917 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011918 }
11919
Eric Andersenc470f442003-07-28 09:56:35 +000011920 n = list(2);
11921
11922 if (oldstyle)
11923 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011924 else if (readtoken() != TRP)
11925 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011926
11927 (*nlpp)->n = n;
11928 if (oldstyle) {
11929 /*
11930 * Start reading from old file again, ignoring any pushed back
11931 * tokens left from the backquote parsing
11932 */
11933 popfile();
11934 tokpushback = 0;
11935 }
11936 while (stackblocksize() <= savelen)
11937 growstackblock();
11938 STARTSTACKSTR(out);
11939 if (str) {
11940 memcpy(out, str, savelen);
11941 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011942 }
Ron Yorston549deab2015-05-18 09:57:51 +020011943 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011944 if (oldstyle)
11945 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011946 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011947}
11948
Mike Frysinger98c52642009-04-02 10:02:37 +000011949#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011950/*
11951 * Parse an arithmetic expansion (indicate start of one and set state)
11952 */
Eric Andersenc470f442003-07-28 09:56:35 +000011953parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011954 if (++arinest == 1) {
11955 prevsyntax = syntax;
11956 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011957 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011958 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011959 goto parsearith_return;
11960}
11961#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011962} /* end of readtoken */
11963
Eric Andersencb57d552001-06-28 07:25:16 +000011964/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011965 * Read the next input token.
11966 * If the token is a word, we set backquotelist to the list of cmds in
11967 * backquotes. We set quoteflag to true if any part of the word was
11968 * quoted.
11969 * If the token is TREDIR, then we set redirnode to a structure containing
11970 * the redirection.
11971 * In all cases, the variable startlinno is set to the number of the line
11972 * on which the token starts.
11973 *
11974 * [Change comment: here documents and internal procedures]
11975 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11976 * word parsing code into a separate routine. In this case, readtoken
11977 * doesn't need to have any internal procedures, but parseword does.
11978 * We could also make parseoperator in essence the main routine, and
11979 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011980 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011981#define NEW_xxreadtoken
11982#ifdef NEW_xxreadtoken
11983/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011984static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011985 '\n', '(', ')', /* singles */
11986 '&', '|', ';', /* doubles */
11987 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011988};
Eric Andersencb57d552001-06-28 07:25:16 +000011989
Denis Vlasenko834dee72008-10-07 09:18:30 +000011990#define xxreadtoken_singles 3
11991#define xxreadtoken_doubles 3
11992
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011993static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011994 TNL, TLP, TRP, /* only single occurrence allowed */
11995 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11996 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011997 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011998};
11999
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012000static int
12001xxreadtoken(void)
12002{
12003 int c;
12004
12005 if (tokpushback) {
12006 tokpushback = 0;
12007 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000012008 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012009 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012010 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012011 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012012 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000012013 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012014 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012015
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012016 if (c == '#') {
12017 while ((c = pgetc()) != '\n' && c != PEOF)
12018 continue;
12019 pungetc();
12020 } else if (c == '\\') {
12021 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012022 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012023 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012024 }
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012025 nlprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012026 } else {
12027 const char *p;
12028
12029 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
12030 if (c != PEOF) {
12031 if (c == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012032 nlnoprompt();
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012033 }
12034
12035 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000012036 if (p == NULL)
12037 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012038
Denis Vlasenko834dee72008-10-07 09:18:30 +000012039 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
12040 int cc = pgetc();
12041 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012042 p += xxreadtoken_doubles + 1;
12043 } else {
12044 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000012045#if ENABLE_ASH_BASH_COMPAT
12046 if (c == '&' && cc == '>') /* &> */
12047 break; /* return readtoken1(...) */
12048#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012049 }
12050 }
12051 }
12052 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12053 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012054 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012055 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012056
12057 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012058}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012059#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012060#define RETURN(token) return lasttoken = token
12061static int
12062xxreadtoken(void)
12063{
12064 int c;
12065
12066 if (tokpushback) {
12067 tokpushback = 0;
12068 return lasttoken;
12069 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012070 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012071 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012072 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012073 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012074 switch (c) {
12075 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012076 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012077 continue;
12078 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012079 while ((c = pgetc()) != '\n' && c != PEOF)
12080 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012081 pungetc();
12082 continue;
12083 case '\\':
12084 if (pgetc() == '\n') {
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012085 nlprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012086 continue;
12087 }
12088 pungetc();
12089 goto breakloop;
12090 case '\n':
Denys Vlasenkoce332a22016-10-02 23:47:34 +020012091 nlnoprompt();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012092 RETURN(TNL);
12093 case PEOF:
12094 RETURN(TEOF);
12095 case '&':
12096 if (pgetc() == '&')
12097 RETURN(TAND);
12098 pungetc();
12099 RETURN(TBACKGND);
12100 case '|':
12101 if (pgetc() == '|')
12102 RETURN(TOR);
12103 pungetc();
12104 RETURN(TPIPE);
12105 case ';':
12106 if (pgetc() == ';')
12107 RETURN(TENDCASE);
12108 pungetc();
12109 RETURN(TSEMI);
12110 case '(':
12111 RETURN(TLP);
12112 case ')':
12113 RETURN(TRP);
12114 default:
12115 goto breakloop;
12116 }
12117 }
12118 breakloop:
12119 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12120#undef RETURN
12121}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012122#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012123
12124static int
12125readtoken(void)
12126{
12127 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012128 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012129#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012130 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012131#endif
12132
12133#if ENABLE_ASH_ALIAS
12134 top:
12135#endif
12136
12137 t = xxreadtoken();
12138
12139 /*
12140 * eat newlines
12141 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012142 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012143 while (t == TNL) {
12144 parseheredoc();
12145 t = xxreadtoken();
12146 }
12147 }
12148
12149 if (t != TWORD || quoteflag) {
12150 goto out;
12151 }
12152
12153 /*
12154 * check for keywords
12155 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012156 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012157 const char *const *pp;
12158
12159 pp = findkwd(wordtext);
12160 if (pp) {
12161 lasttoken = t = pp - tokname_array;
Denys Vlasenko888527c2016-10-02 16:54:17 +020012162 TRACE(("keyword '%s' recognized\n", tokname_array[t]));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012163 goto out;
12164 }
12165 }
12166
12167 if (checkkwd & CHKALIAS) {
12168#if ENABLE_ASH_ALIAS
12169 struct alias *ap;
12170 ap = lookupalias(wordtext, 1);
12171 if (ap != NULL) {
12172 if (*ap->val) {
12173 pushstring(ap->val, ap);
12174 }
12175 goto top;
12176 }
12177#endif
12178 }
12179 out:
12180 checkkwd = 0;
12181#if DEBUG
12182 if (!alreadyseen)
Denys Vlasenko888527c2016-10-02 16:54:17 +020012183 TRACE(("token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012184 else
Denys Vlasenko888527c2016-10-02 16:54:17 +020012185 TRACE(("reread token '%s' %s\n", tokname_array[t], t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012186#endif
12187 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012188}
12189
Ron Yorstonc0e00762015-10-29 11:30:55 +000012190static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012191peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012192{
12193 int t;
12194
12195 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012196 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012197 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012198}
Eric Andersencb57d552001-06-28 07:25:16 +000012199
12200/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012201 * Read and parse a command. Returns NODE_EOF on end of file.
12202 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012203 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012204static union node *
12205parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012206{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012207 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012208 checkkwd = 0;
12209 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012210 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012211 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012212 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012213 return list(1);
12214}
12215
12216/*
12217 * Input any here documents.
12218 */
12219static void
12220parseheredoc(void)
12221{
12222 struct heredoc *here;
12223 union node *n;
12224
12225 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012226 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012227
12228 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012229 setprompt_if(needprompt, 2);
12230 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012231 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012232 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012233 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012234 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012235 n->narg.text = wordtext;
12236 n->narg.backquote = backquotelist;
12237 here->here->nhere.doc = n;
12238 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012239 }
Eric Andersencb57d552001-06-28 07:25:16 +000012240}
12241
12242
12243/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012244 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012245 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012246#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012247static const char *
12248expandstr(const char *ps)
12249{
12250 union node n;
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012251 int saveprompt;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012252
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012253 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12254 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012255 setinputstring((char *)ps);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012256
12257 saveprompt = doprompt;
12258 doprompt = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000012259 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
Denys Vlasenko2a6d29a2016-10-25 21:17:52 +020012260 doprompt = saveprompt;
12261
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012262 popfile();
12263
12264 n.narg.type = NARG;
12265 n.narg.next = NULL;
12266 n.narg.text = wordtext;
12267 n.narg.backquote = backquotelist;
12268
Ron Yorston549deab2015-05-18 09:57:51 +020012269 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012270 return stackblock();
12271}
12272#endif
12273
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012274/*
12275 * Execute a command or commands contained in a string.
12276 */
12277static int
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012278evalstring(char *s, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000012279{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012280 union node *n;
12281 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012282 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012283
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012284 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012285 setinputstring(s);
12286 setstackmark(&smark);
12287
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012288 status = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012289 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012290 int i;
12291
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012292 i = evaltree(n, flags);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012293 if (n)
12294 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012295 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012296 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012297 break;
12298 }
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012299 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012300 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012301 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012302
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012303 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012304}
12305
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012306/*
12307 * The eval command.
12308 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012309static int FAST_FUNC
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012310evalcmd(int argc UNUSED_PARAM, char **argv, int flags)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012311{
12312 char *p;
12313 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012314
Denis Vlasenko68404f12008-03-17 09:00:54 +000012315 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012316 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012317 argv += 2;
12318 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012319 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012320 for (;;) {
12321 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012322 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012323 if (p == NULL)
12324 break;
12325 STPUTC(' ', concat);
12326 }
12327 STPUTC('\0', concat);
12328 p = grabstackstr(concat);
12329 }
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020012330 return evalstring(p, flags & EV_TESTED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012331 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012332 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012333}
12334
12335/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012336 * Read and execute commands.
12337 * "Top" is nonzero for the top level command loop;
12338 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012339 */
12340static int
12341cmdloop(int top)
12342{
12343 union node *n;
12344 struct stackmark smark;
12345 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012346 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012347 int numeof = 0;
12348
12349 TRACE(("cmdloop(%d) called\n", top));
12350 for (;;) {
12351 int skip;
12352
12353 setstackmark(&smark);
12354#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012355 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012356 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012357#endif
12358 inter = 0;
12359 if (iflag && top) {
12360 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012361 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012362 }
12363 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012364#if DEBUG
12365 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012366 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012367#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012368 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012369 if (!top || numeof >= 50)
12370 break;
12371 if (!stoppedjobs()) {
12372 if (!Iflag)
12373 break;
12374 out2str("\nUse \"exit\" to leave shell.\n");
12375 }
12376 numeof++;
12377 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012378 int i;
12379
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012380 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12381 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012382 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012383 i = evaltree(n, 0);
12384 if (n)
12385 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012386 }
12387 popstackmark(&smark);
12388 skip = evalskip;
12389
12390 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012391 evalskip &= ~SKIPFUNC;
Denys Vlasenko0840c912016-10-01 15:27:44 +020012392 break;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012393 }
12394 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012395 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012396}
12397
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012398/*
12399 * Take commands from a file. To be compatible we should do a path
12400 * search for the file, which is necessary to find sub-commands.
12401 */
12402static char *
12403find_dot_file(char *name)
12404{
12405 char *fullname;
12406 const char *path = pathval();
12407 struct stat statb;
12408
12409 /* don't try this for absolute or relative paths */
12410 if (strchr(name, '/'))
12411 return name;
12412
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012413 /* IIRC standards do not say whether . is to be searched.
12414 * And it is even smaller this way, making it unconditional for now:
12415 */
12416 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12417 fullname = name;
12418 goto try_cur_dir;
12419 }
12420
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012421 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012422 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012423 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12424 /*
12425 * Don't bother freeing here, since it will
12426 * be freed by the caller.
12427 */
12428 return fullname;
12429 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012430 if (fullname != name)
12431 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012432 }
12433
12434 /* not found in the PATH */
12435 ash_msg_and_raise_error("%s: not found", name);
12436 /* NOTREACHED */
12437}
12438
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012439static int FAST_FUNC
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012440dotcmd(int argc_ UNUSED_PARAM, char **argv_ UNUSED_PARAM)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012441{
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012442 /* "false; . empty_file; echo $?" should print 0, not 1: */
12443 int status = 0;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012444 char *fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012445 char **argv;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012446 struct strlist *sp;
12447 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012448
12449 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012450 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012451
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012452 nextopt(nullstr); /* handle possible "--" */
12453 argv = argptr;
12454
12455 if (!argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012456 /* bash says: "bash: .: filename argument required" */
12457 return 2; /* bash compat */
12458 }
12459
Denys Vlasenko091f8312013-03-17 14:25:22 +010012460 /* This aborts if file isn't found, which is POSIXly correct.
12461 * bash returns exitcode 1 instead.
12462 */
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012463 fullname = find_dot_file(argv[0]);
12464 argv++;
12465 if (argv[0]) { /* . FILE ARGS, ARGS exist */
12466 int argc;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012467 saveparam = shellparam;
12468 shellparam.malloced = 0;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012469 argc = 1;
12470 while (argv[argc])
12471 argc++;
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012472 shellparam.nparam = argc;
12473 shellparam.p = argv;
12474 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012475
Denys Vlasenko091f8312013-03-17 14:25:22 +010012476 /* This aborts if file can't be opened, which is POSIXly correct.
12477 * bash returns exitcode 1 instead.
12478 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012479 setinputfile(fullname, INPUT_PUSH_FILE);
12480 commandname = fullname;
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012481 status = cmdloop(0);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012482 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012483
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012484 if (argv[0]) {
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012485 freeparam(&shellparam);
12486 shellparam = saveparam;
12487 };
12488
Denys Vlasenko0cdb7ea2016-10-02 03:16:00 +020012489 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012490}
12491
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012492static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012493exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012494{
12495 if (stoppedjobs())
12496 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012497 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012498 exitstatus = number(argv[1]);
12499 raise_exception(EXEXIT);
12500 /* NOTREACHED */
12501}
12502
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012503/*
12504 * Read a file containing shell functions.
12505 */
12506static void
12507readcmdfile(char *name)
12508{
12509 setinputfile(name, INPUT_PUSH_FILE);
12510 cmdloop(0);
12511 popfile();
12512}
12513
12514
Denis Vlasenkocc571512007-02-23 21:10:35 +000012515/* ============ find_command inplementation */
12516
12517/*
12518 * Resolve a command name. If you change this routine, you may have to
12519 * change the shellexec routine as well.
12520 */
12521static void
12522find_command(char *name, struct cmdentry *entry, int act, const char *path)
12523{
12524 struct tblentry *cmdp;
12525 int idx;
12526 int prev;
12527 char *fullname;
12528 struct stat statb;
12529 int e;
12530 int updatetbl;
12531 struct builtincmd *bcmd;
12532
12533 /* If name contains a slash, don't use PATH or hash table */
12534 if (strchr(name, '/') != NULL) {
12535 entry->u.index = -1;
12536 if (act & DO_ABS) {
12537 while (stat(name, &statb) < 0) {
12538#ifdef SYSV
12539 if (errno == EINTR)
12540 continue;
12541#endif
12542 entry->cmdtype = CMDUNKNOWN;
12543 return;
12544 }
12545 }
12546 entry->cmdtype = CMDNORMAL;
12547 return;
12548 }
12549
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012550/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012551
12552 updatetbl = (path == pathval());
12553 if (!updatetbl) {
12554 act |= DO_ALTPATH;
12555 if (strstr(path, "%builtin") != NULL)
12556 act |= DO_ALTBLTIN;
12557 }
12558
12559 /* If name is in the table, check answer will be ok */
12560 cmdp = cmdlookup(name, 0);
12561 if (cmdp != NULL) {
12562 int bit;
12563
12564 switch (cmdp->cmdtype) {
12565 default:
12566#if DEBUG
12567 abort();
12568#endif
12569 case CMDNORMAL:
12570 bit = DO_ALTPATH;
12571 break;
12572 case CMDFUNCTION:
12573 bit = DO_NOFUNC;
12574 break;
12575 case CMDBUILTIN:
12576 bit = DO_ALTBLTIN;
12577 break;
12578 }
12579 if (act & bit) {
12580 updatetbl = 0;
12581 cmdp = NULL;
12582 } else if (cmdp->rehash == 0)
12583 /* if not invalidated by cd, we're done */
12584 goto success;
12585 }
12586
12587 /* If %builtin not in path, check for builtin next */
12588 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012589 if (bcmd) {
12590 if (IS_BUILTIN_REGULAR(bcmd))
12591 goto builtin_success;
12592 if (act & DO_ALTPATH) {
12593 if (!(act & DO_ALTBLTIN))
12594 goto builtin_success;
12595 } else if (builtinloc <= 0) {
12596 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012597 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012598 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012599
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012600#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012601 {
12602 int applet_no = find_applet_by_name(name);
12603 if (applet_no >= 0) {
12604 entry->cmdtype = CMDNORMAL;
12605 entry->u.index = -2 - applet_no;
12606 return;
12607 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012608 }
12609#endif
12610
Denis Vlasenkocc571512007-02-23 21:10:35 +000012611 /* We have to search path. */
12612 prev = -1; /* where to start */
12613 if (cmdp && cmdp->rehash) { /* doing a rehash */
12614 if (cmdp->cmdtype == CMDBUILTIN)
12615 prev = builtinloc;
12616 else
12617 prev = cmdp->param.index;
12618 }
12619
12620 e = ENOENT;
12621 idx = -1;
12622 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012623 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012624 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012625 /* NB: code below will still use fullname
12626 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012627 idx++;
12628 if (pathopt) {
12629 if (prefix(pathopt, "builtin")) {
12630 if (bcmd)
12631 goto builtin_success;
12632 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012633 }
12634 if ((act & DO_NOFUNC)
12635 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012636 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012637 continue;
12638 }
12639 }
12640 /* if rehash, don't redo absolute path names */
12641 if (fullname[0] == '/' && idx <= prev) {
12642 if (idx < prev)
12643 continue;
12644 TRACE(("searchexec \"%s\": no change\n", name));
12645 goto success;
12646 }
12647 while (stat(fullname, &statb) < 0) {
12648#ifdef SYSV
12649 if (errno == EINTR)
12650 continue;
12651#endif
12652 if (errno != ENOENT && errno != ENOTDIR)
12653 e = errno;
12654 goto loop;
12655 }
12656 e = EACCES; /* if we fail, this will be the error */
12657 if (!S_ISREG(statb.st_mode))
12658 continue;
12659 if (pathopt) { /* this is a %func directory */
12660 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012661 /* NB: stalloc will return space pointed by fullname
12662 * (because we don't have any intervening allocations
12663 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012664 readcmdfile(fullname);
12665 cmdp = cmdlookup(name, 0);
12666 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12667 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12668 stunalloc(fullname);
12669 goto success;
12670 }
12671 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12672 if (!updatetbl) {
12673 entry->cmdtype = CMDNORMAL;
12674 entry->u.index = idx;
12675 return;
12676 }
12677 INT_OFF;
12678 cmdp = cmdlookup(name, 1);
12679 cmdp->cmdtype = CMDNORMAL;
12680 cmdp->param.index = idx;
12681 INT_ON;
12682 goto success;
12683 }
12684
12685 /* We failed. If there was an entry for this command, delete it */
12686 if (cmdp && updatetbl)
12687 delete_cmd_entry();
12688 if (act & DO_ERR)
12689 ash_msg("%s: %s", name, errmsg(e, "not found"));
12690 entry->cmdtype = CMDUNKNOWN;
12691 return;
12692
12693 builtin_success:
12694 if (!updatetbl) {
12695 entry->cmdtype = CMDBUILTIN;
12696 entry->u.cmd = bcmd;
12697 return;
12698 }
12699 INT_OFF;
12700 cmdp = cmdlookup(name, 1);
12701 cmdp->cmdtype = CMDBUILTIN;
12702 cmdp->param.cmd = bcmd;
12703 INT_ON;
12704 success:
12705 cmdp->rehash = 0;
12706 entry->cmdtype = cmdp->cmdtype;
12707 entry->u = cmdp->param;
12708}
12709
12710
Eric Andersencb57d552001-06-28 07:25:16 +000012711/*
Eric Andersencb57d552001-06-28 07:25:16 +000012712 * The trap builtin.
12713 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012714static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012715trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012716{
12717 char *action;
12718 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012719 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012720
Eric Andersenc470f442003-07-28 09:56:35 +000012721 nextopt(nullstr);
12722 ap = argptr;
12723 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012724 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012725 char *tr = trap_ptr[signo];
12726 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012727 /* note: bash adds "SIG", but only if invoked
12728 * as "bash". If called as "sh", or if set -o posix,
12729 * then it prints short signal names.
12730 * We are printing short names: */
12731 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012732 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012733 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012734 /* trap_ptr != trap only if we are in special-cased `trap` code.
12735 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012736 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012737 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012738 }
12739 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012740 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012741 if (trap_ptr != trap) {
12742 free(trap_ptr);
12743 trap_ptr = trap;
12744 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012745 */
Eric Andersencb57d552001-06-28 07:25:16 +000012746 return 0;
12747 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012748
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012749 action = NULL;
12750 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012751 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012752 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012753 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012754 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012755 if (signo < 0) {
12756 /* Mimic bash message exactly */
12757 ash_msg("%s: invalid signal specification", *ap);
12758 exitcode = 1;
12759 goto next;
12760 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012761 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012762 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012763 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012764 action = NULL;
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012765 else {
12766 if (action[0]) /* not NULL and not "" and not "-" */
12767 may_have_traps = 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012768 action = ckstrdup(action);
Denys Vlasenkob4f51d32016-10-27 12:55:09 +020012769 }
Eric Andersencb57d552001-06-28 07:25:16 +000012770 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012771 free(trap[signo]);
Eric Andersencb57d552001-06-28 07:25:16 +000012772 trap[signo] = action;
12773 if (signo != 0)
12774 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012775 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012776 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012777 ap++;
12778 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012779 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012780}
12781
Eric Andersenc470f442003-07-28 09:56:35 +000012782
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012783/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012784
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012785#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012786static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012787helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012788{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012789 unsigned col;
12790 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012791
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012792 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012793 "Built-in commands:\n"
12794 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012795 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012796 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012797 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012798 if (col > 60) {
12799 out1fmt("\n");
12800 col = 0;
12801 }
12802 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012803# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012804 {
12805 const char *a = applet_names;
12806 while (*a) {
12807 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12808 if (col > 60) {
12809 out1fmt("\n");
12810 col = 0;
12811 }
Ron Yorston2b919582016-04-08 11:57:20 +010012812 while (*a++ != '\0')
12813 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012814 }
12815 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012816# endif
Denys Vlasenkoebedb942016-10-02 18:45:09 +020012817 newline_and_flush(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +000012818 return EXIT_SUCCESS;
12819}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012820#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012821
Flemming Madsend96ffda2013-04-07 18:47:24 +020012822#if MAX_HISTORY
12823static int FAST_FUNC
12824historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12825{
12826 show_history(line_input_state);
12827 return EXIT_SUCCESS;
12828}
12829#endif
12830
Eric Andersencb57d552001-06-28 07:25:16 +000012831/*
Eric Andersencb57d552001-06-28 07:25:16 +000012832 * The export and readonly commands.
12833 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012834static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012835exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012836{
12837 struct var *vp;
12838 char *name;
12839 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012840 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012841 char opt;
12842 int flag;
12843 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012844
Denys Vlasenkod5275882012-10-01 13:41:17 +020012845 /* "readonly" in bash accepts, but ignores -n.
12846 * We do the same: it saves a conditional in nextopt's param.
12847 */
12848 flag_off = 0;
12849 while ((opt = nextopt("np")) != '\0') {
12850 if (opt == 'n')
12851 flag_off = VEXPORT;
12852 }
12853 flag = VEXPORT;
12854 if (argv[0][0] == 'r') {
12855 flag = VREADONLY;
12856 flag_off = 0; /* readonly ignores -n */
12857 }
12858 flag_off = ~flag_off;
12859
12860 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12861 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012862 aptr = argptr;
12863 name = *aptr;
12864 if (name) {
12865 do {
12866 p = strchr(name, '=');
12867 if (p != NULL) {
12868 p++;
12869 } else {
12870 vp = *findvar(hashvar(name), name);
12871 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012872 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012873 continue;
12874 }
Eric Andersencb57d552001-06-28 07:25:16 +000012875 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012876 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012877 } while ((name = *++aptr) != NULL);
12878 return 0;
12879 }
Eric Andersencb57d552001-06-28 07:25:16 +000012880 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012881
12882 /* No arguments. Show the list of exported or readonly vars.
12883 * -n is ignored.
12884 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012885 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012886 return 0;
12887}
12888
Eric Andersencb57d552001-06-28 07:25:16 +000012889/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012890 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012891 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012892static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012893unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012894{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012895 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012896
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012897 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012898 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012899 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012900}
12901
Eric Andersencb57d552001-06-28 07:25:16 +000012902/*
Eric Andersencb57d552001-06-28 07:25:16 +000012903 * The unset builtin command. We unset the function before we unset the
12904 * variable to allow a function to be unset when there is a readonly variable
12905 * with the same name.
12906 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012907static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012908unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012909{
12910 char **ap;
12911 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012912 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012913 int ret = 0;
12914
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012915 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012916 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012917 }
Eric Andersencb57d552001-06-28 07:25:16 +000012918
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012919 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012920 if (flag != 'f') {
12921 i = unsetvar(*ap);
12922 ret |= i;
12923 if (!(i & 2))
12924 continue;
12925 }
12926 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012927 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012928 }
Eric Andersenc470f442003-07-28 09:56:35 +000012929 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012930}
12931
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012932static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012933 ' ', offsetof(struct tms, tms_utime),
12934 '\n', offsetof(struct tms, tms_stime),
12935 ' ', offsetof(struct tms, tms_cutime),
12936 '\n', offsetof(struct tms, tms_cstime),
12937 0
12938};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012939static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012940timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012941{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012942 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012943 const unsigned char *p;
12944 struct tms buf;
12945
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012946 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012947 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012948
12949 p = timescmd_str;
12950 do {
12951 t = *(clock_t *)(((char *) &buf) + p[1]);
12952 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012953 t = t % clk_tck;
12954 out1fmt("%lum%lu.%03lus%c",
12955 s / 60, s % 60,
12956 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012957 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012958 p += 2;
12959 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012960
Eric Andersencb57d552001-06-28 07:25:16 +000012961 return 0;
12962}
12963
Mike Frysinger98c52642009-04-02 10:02:37 +000012964#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012965/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012966 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012967 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012968 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012969 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012970 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012971static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012972letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012973{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012974 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012975
Denis Vlasenko68404f12008-03-17 09:00:54 +000012976 argv++;
12977 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012978 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012979 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012980 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012981 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012982
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012983 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012984}
Eric Andersenc470f442003-07-28 09:56:35 +000012985#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012986
Eric Andersenc470f442003-07-28 09:56:35 +000012987/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012988 * The read builtin. Options:
12989 * -r Do not interpret '\' specially
12990 * -s Turn off echo (tty only)
12991 * -n NCHARS Read NCHARS max
12992 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12993 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12994 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012995 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012996 * TODO: bash also has:
12997 * -a ARRAY Read into array[0],[1],etc
12998 * -d DELIM End on DELIM char, not newline
12999 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000013000 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013001static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013002readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013003{
Denys Vlasenko73067272010-01-12 22:11:24 +010013004 char *opt_n = NULL;
13005 char *opt_p = NULL;
13006 char *opt_t = NULL;
13007 char *opt_u = NULL;
13008 int read_flags = 0;
13009 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000013010 int i;
13011
Denys Vlasenko73067272010-01-12 22:11:24 +010013012 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000013013 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000013014 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010013015 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013016 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013017 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010013018 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013019 break;
13020 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010013021 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000013022 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013023 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010013024 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000013025 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013026 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010013027 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000013028 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013029 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010013030 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000013031 break;
Paul Fox02eb9342005-09-07 16:56:02 +000013032 default:
13033 break;
13034 }
Eric Andersenc470f442003-07-28 09:56:35 +000013035 }
Paul Fox02eb9342005-09-07 16:56:02 +000013036
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013037 /* "read -s" needs to save/restore termios, can't allow ^C
13038 * to jump out of it.
13039 */
13040 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013041 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010013042 argptr,
13043 bltinlookup("IFS"), /* can be NULL */
13044 read_flags,
13045 opt_n,
13046 opt_p,
13047 opt_t,
13048 opt_u
13049 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020013050 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000013051
Denys Vlasenko73067272010-01-12 22:11:24 +010013052 if ((uintptr_t)r > 1)
13053 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000013054
Denys Vlasenko73067272010-01-12 22:11:24 +010013055 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000013056}
13057
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013058static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020013059umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000013060{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013061 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013062
Eric Andersenc470f442003-07-28 09:56:35 +000013063 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013064 int symbolic_mode = 0;
13065
13066 while (nextopt("S") != '\0') {
13067 symbolic_mode = 1;
13068 }
13069
Denis Vlasenkob012b102007-02-19 22:43:01 +000013070 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013071 mask = umask(0);
13072 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013073 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013074
Denys Vlasenko6283f982015-10-07 16:56:20 +020013075 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013076 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013077 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013078 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013079 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013080
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013081 i = 2;
13082 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013083 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013084 *p++ = permuser[i];
13085 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013086 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013087 if (!(mask & 0400)) *p++ = 'r';
13088 if (!(mask & 0200)) *p++ = 'w';
13089 if (!(mask & 0100)) *p++ = 'x';
13090 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013091 if (--i < 0)
13092 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013093 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013094 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013095 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013096 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013097 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013098 }
13099 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013100 char *modestr = *argptr;
13101 /* numeric umasks are taken as-is */
13102 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13103 if (!isdigit(modestr[0]))
13104 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013105 mask = bb_parse_mode(modestr, mask);
13106 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013107 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013108 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013109 if (!isdigit(modestr[0]))
13110 mask ^= 0777;
13111 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013112 }
13113 return 0;
13114}
13115
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013116static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013117ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013118{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013119 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013120}
13121
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013122/* ============ main() and helpers */
13123
13124/*
13125 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013126 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013127static void
13128exitshell(void)
13129{
13130 struct jmploc loc;
13131 char *p;
13132 int status;
13133
Denys Vlasenkobede2152011-09-04 16:12:33 +020013134#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13135 save_history(line_input_state);
13136#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013137 status = exitstatus;
13138 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13139 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013140 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013141 status = exitstatus;
13142 goto out;
13143 }
13144 exception_handler = &loc;
13145 p = trap[0];
13146 if (p) {
13147 trap[0] = NULL;
Denys Vlasenko7b3fa1e2016-10-01 15:10:16 +020013148 evalskip = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013149 evalstring(p, 0);
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013150 /*free(p); - we'll exit soon */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013151 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013152 out:
Denys Vlasenkof37e1152016-10-07 03:17:28 +020013153 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
13154 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
13155 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013156 setjobctl(0);
Denys Vlasenkocaee80c2016-10-25 20:49:53 +020013157 flush_stdout_stderr();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013158 _exit(status);
13159 /* NOTREACHED */
13160}
13161
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013162static void
13163init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013164{
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013165 /* we will never free this */
13166 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013167
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013168 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013169 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13170 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13171 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013172 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013173
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013174 {
13175 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013176 const char *p;
13177 struct stat st1, st2;
13178
13179 initvar();
13180 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013181 p = endofname(*envp);
13182 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013183 setvareq(*envp, VEXPORT|VTEXTFIXED);
13184 }
13185 }
13186
Denys Vlasenkoe627ac92016-09-30 14:36:59 +020013187 setvareq((char*)defoptindvar, VTEXTFIXED);
13188
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013189 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013190#if ENABLE_ASH_BASH_COMPAT
13191 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013192 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013193 if (!lookupvar("HOSTNAME")) {
13194 struct utsname uts;
13195 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013196 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013197 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013198#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013199 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013200 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013201 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013202 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13203 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013204 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013205 }
13206 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013207 setpwd(p, 0);
13208 }
13209}
13210
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013211
13212//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013213//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013214//usage:#define ash_full_usage "\n\n"
13215//usage: "Unix shell interpreter"
13216
13217//usage:#if ENABLE_FEATURE_SH_IS_ASH
13218//usage:# define sh_trivial_usage ash_trivial_usage
13219//usage:# define sh_full_usage ash_full_usage
13220//usage:#endif
13221//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13222//usage:# define bash_trivial_usage ash_trivial_usage
13223//usage:# define bash_full_usage ash_full_usage
13224//usage:#endif
13225
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013226/*
13227 * Process the shell command line arguments.
13228 */
13229static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013230procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013231{
13232 int i;
13233 const char *xminusc;
13234 char **xargv;
13235
13236 xargv = argv;
13237 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013238 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013239 xargv++;
13240 for (i = 0; i < NOPTS; i++)
13241 optlist[i] = 2;
13242 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013243 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013244 /* it already printed err message */
13245 raise_exception(EXERROR);
13246 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013247 xargv = argptr;
13248 xminusc = minusc;
13249 if (*xargv == NULL) {
13250 if (xminusc)
13251 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13252 sflag = 1;
13253 }
13254 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13255 iflag = 1;
13256 if (mflag == 2)
13257 mflag = iflag;
13258 for (i = 0; i < NOPTS; i++)
13259 if (optlist[i] == 2)
13260 optlist[i] = 0;
13261#if DEBUG == 2
13262 debug = 1;
13263#endif
13264 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13265 if (xminusc) {
13266 minusc = *xargv++;
13267 if (*xargv)
13268 goto setarg0;
13269 } else if (!sflag) {
13270 setinputfile(*xargv, 0);
13271 setarg0:
13272 arg0 = *xargv++;
13273 commandname = arg0;
13274 }
13275
13276 shellparam.p = xargv;
13277#if ENABLE_ASH_GETOPTS
13278 shellparam.optind = 1;
13279 shellparam.optoff = -1;
13280#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013281 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013282 while (*xargv) {
13283 shellparam.nparam++;
13284 xargv++;
13285 }
13286 optschanged();
13287}
13288
13289/*
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013290 * Read /etc/profile, ~/.profile, $ENV.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013291 */
13292static void
13293read_profile(const char *name)
13294{
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013295 name = expandstr(name);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013296 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13297 return;
Denys Vlasenko0840c912016-10-01 15:27:44 +020013298 cmdloop(0);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013299 popfile();
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013300}
13301
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013302/*
13303 * This routine is called when an error or an interrupt occurs in an
13304 * interactive shell and control is returned to the main command loop.
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013305 * (In dash, this function is auto-generated by build machinery).
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013306 */
13307static void
13308reset(void)
13309{
13310 /* from eval.c: */
13311 evalskip = 0;
13312 loopnest = 0;
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013313
13314 /* from expand.c: */
13315 ifsfree();
13316
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013317 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013318 g_parsefile->left_in_buffer = 0;
13319 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013320 popallfiles();
Denys Vlasenko5ac04f22016-10-27 14:46:50 +020013321
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013322 /* from redir.c: */
Denys Vlasenkoe19923f2016-10-26 15:38:44 +020013323 while (redirlist)
13324 popredir(/*drop:*/ 0, /*restore:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013325}
13326
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013327#if PROFILE
13328static short profile_buf[16384];
13329extern int etext();
13330#endif
13331
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013332/*
13333 * Main routine. We initialize things, parse the arguments, execute
13334 * profiles if we're a login shell, and then call cmdloop to execute
13335 * commands. The setjmp call sets up the location to jump to when an
13336 * exception occurs. When an exception occurs the variable "state"
13337 * is used to figure out how far we had gotten.
13338 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013339int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013340int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013341{
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013342 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013343 struct jmploc jmploc;
13344 struct stackmark smark;
13345
Denis Vlasenko01631112007-12-16 17:20:38 +000013346 /* Initialize global data */
13347 INIT_G_misc();
13348 INIT_G_memstack();
13349 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013350#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013351 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013352#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013353 INIT_G_cmdtable();
13354
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013355#if PROFILE
13356 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13357#endif
13358
13359#if ENABLE_FEATURE_EDITING
13360 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13361#endif
13362 state = 0;
13363 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013364 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013365 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013366
13367 reset();
13368
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013369 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013370 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013371 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013372 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013373 }
13374 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013375 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013376 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013377
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013378 popstackmark(&smark);
13379 FORCE_INT_ON; /* enable interrupts */
13380 if (s == 1)
13381 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013382 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013383 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013384 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013385 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013386 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013387 }
13388 exception_handler = &jmploc;
13389#if DEBUG
13390 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013391 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013392 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013393#endif
13394 rootpid = getpid();
13395
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013396 init();
13397 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013398 procargs(argv);
13399
Denys Vlasenko6088e132010-12-25 23:58:42 +010013400 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013401 isloginsh = 1;
13402 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013403 const char *hp;
13404
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013405 state = 1;
13406 read_profile("/etc/profile");
13407 state1:
13408 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013409 hp = lookupvar("HOME");
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013410 if (hp)
13411 read_profile("$HOME/.profile");
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013412 }
13413 state2:
13414 state = 3;
13415 if (
13416#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013417 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013418#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013419 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013420 ) {
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013421 const char *shinit = lookupvar("ENV");
13422 if (shinit != NULL && *shinit != '\0')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013423 read_profile(shinit);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013424 }
Denys Vlasenko2eb0a7e2016-10-27 11:28:59 +020013425 popstackmark(&smark);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013426 state3:
13427 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013428 if (minusc) {
13429 /* evalstring pushes parsefile stack.
13430 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013431 * is one of stacked source fds.
13432 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013433 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013434 // ^^ not necessary since now we special-case fd 0
13435 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013436 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013437 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013438
13439 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013440#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013441 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013442 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013443 if (!hp) {
13444 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013445 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013446 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013447 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013448 free((char*)hp);
13449 hp = lookupvar("HISTFILE");
13450 }
13451 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013452 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013453 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013454# if ENABLE_FEATURE_SH_HISTFILESIZE
13455 hp = lookupvar("HISTFILESIZE");
13456 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13457# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013458 }
13459#endif
13460 state4: /* XXX ??? - why isn't this before the "if" statement */
13461 cmdloop(1);
13462 }
13463#if PROFILE
13464 monitor(0);
13465#endif
13466#ifdef GPROF
13467 {
13468 extern void _mcleanup(void);
13469 _mcleanup();
13470 }
13471#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013472 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013473 exitshell();
13474 /* NOTREACHED */
13475}
13476
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013477
Eric Andersendf82f612001-06-28 07:46:40 +000013478/*-
13479 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013480 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013481 *
13482 * This code is derived from software contributed to Berkeley by
13483 * Kenneth Almquist.
13484 *
13485 * Redistribution and use in source and binary forms, with or without
13486 * modification, are permitted provided that the following conditions
13487 * are met:
13488 * 1. Redistributions of source code must retain the above copyright
13489 * notice, this list of conditions and the following disclaimer.
13490 * 2. Redistributions in binary form must reproduce the above copyright
13491 * notice, this list of conditions and the following disclaimer in the
13492 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013493 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013494 * may be used to endorse or promote products derived from this software
13495 * without specific prior written permission.
13496 *
13497 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13498 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13499 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13500 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13501 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13502 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13503 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13504 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13505 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13506 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13507 * SUCH DAMAGE.
13508 */