blob: 4f6376f787ad2446e1b63eae2d5c726299cf4226 [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 */
46#include "unicode.h"
47
Denys Vlasenko73067272010-01-12 22:11:24 +010048#include "shell_common.h"
Denys Vlasenko26777aa2010-11-22 23:49:10 +010049#if ENABLE_SH_MATH_SUPPORT
50# include "math.h"
51#endif
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020052#if ENABLE_ASH_RANDOM_SUPPORT
53# include "random.h"
Denys Vlasenko36df0482009-10-19 16:07:28 +020054#else
55# define CLEAR_RANDOM_T(rnd) ((void)0)
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020056#endif
Denis Vlasenko61befda2008-11-25 01:36:03 +000057
Denys Vlasenko1fcbff22010-06-26 02:40:08 +020058#include "NUM_APPLETS.h"
Denys Vlasenko14974842010-03-23 01:08:26 +010059#if NUM_APPLETS == 1
Denis Vlasenko61befda2008-11-25 01:36:03 +000060/* STANDALONE does not make sense, and won't compile */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020061# undef CONFIG_FEATURE_SH_STANDALONE
62# undef ENABLE_FEATURE_SH_STANDALONE
63# undef IF_FEATURE_SH_STANDALONE
Denys Vlasenko14974842010-03-23 01:08:26 +010064# undef IF_NOT_FEATURE_SH_STANDALONE
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020065# define ENABLE_FEATURE_SH_STANDALONE 0
66# define IF_FEATURE_SH_STANDALONE(...)
67# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
Eric Andersencb57d552001-06-28 07:25:16 +000068#endif
69
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000070#ifndef PIPE_BUF
Denis Vlasenko653d8e72009-03-19 21:59:35 +000071# define PIPE_BUF 4096 /* amount of buffering in a pipe */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000072#endif
73
Denys Vlasenko153fcaa2010-02-21 05:17:41 +010074#if !BB_MMU
Denis Vlasenko653d8e72009-03-19 21:59:35 +000075# error "Do not even bother, ash will not run on NOMMU machine"
Denis Vlasenkob012b102007-02-19 22:43:01 +000076#endif
77
Denys Vlasenko771f1992010-07-16 14:31:34 +020078//config:config ASH
79//config: bool "ash"
80//config: default y
81//config: depends on !NOMMU
82//config: help
83//config: Tha 'ash' shell adds about 60k in the default configuration and is
84//config: the most complete and most pedantically correct shell included with
85//config: busybox. This shell is actually a derivative of the Debian 'dash'
86//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
87//config: (written by Kenneth Almquist) from NetBSD.
88//config:
89//config:config ASH_BASH_COMPAT
90//config: bool "bash-compatible extensions"
91//config: default y
92//config: depends on ASH
93//config: help
94//config: Enable bash-compatible extensions.
95//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010096//config:config ASH_IDLE_TIMEOUT
97//config: bool "Idle timeout variable"
98//config: default n
99//config: depends on ASH
100//config: help
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100101//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko046341e2011-02-04 17:53:59 +0100102//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200103//config:config ASH_JOB_CONTROL
104//config: bool "Job control"
105//config: default y
106//config: depends on ASH
107//config: help
108//config: Enable job control in the ash shell.
109//config:
110//config:config ASH_ALIAS
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100111//config: bool "Alias support"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200112//config: default y
113//config: depends on ASH
114//config: help
115//config: Enable alias support in the ash shell.
116//config:
117//config:config ASH_GETOPTS
118//config: bool "Builtin getopt to parse positional parameters"
119//config: default y
120//config: depends on ASH
121//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100122//config: Enable support for getopts builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200123//config:
124//config:config ASH_BUILTIN_ECHO
125//config: bool "Builtin version of 'echo'"
126//config: default y
127//config: depends on ASH
128//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100129//config: Enable support for echo builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200130//config:
131//config:config ASH_BUILTIN_PRINTF
132//config: bool "Builtin version of 'printf'"
133//config: default y
134//config: depends on ASH
135//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100136//config: Enable support for printf builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200137//config:
138//config:config ASH_BUILTIN_TEST
139//config: bool "Builtin version of 'test'"
140//config: default y
141//config: depends on ASH
142//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100143//config: Enable support for test builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200144//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200145//config:config ASH_HELP
146//config: bool "help builtin"
147//config: default y
148//config: depends on ASH
149//config: help
150//config: Enable help builtin in ash.
151//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200152//config:config ASH_CMDCMD
153//config: bool "'command' command to override shell builtins"
154//config: default y
155//config: depends on ASH
156//config: help
157//config: Enable support for the ash 'command' builtin, which allows
158//config: you to run the specified command with the specified arguments,
159//config: even when there is an ash builtin command with the same name.
160//config:
161//config:config ASH_MAIL
162//config: bool "Check for new mail on interactive shells"
163//config: default n
164//config: depends on ASH
165//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100166//config: Enable "check for new mail" function in the ash shell.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200167//config:
168//config:config ASH_OPTIMIZE_FOR_SIZE
169//config: bool "Optimize for size instead of speed"
170//config: default y
171//config: depends on ASH
172//config: help
173//config: Compile ash for reduced size at the price of speed.
174//config:
175//config:config ASH_RANDOM_SUPPORT
176//config: bool "Pseudorandom generator and $RANDOM variable"
177//config: default y
178//config: depends on ASH
179//config: help
180//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
181//config: Each read of "$RANDOM" will generate a new pseudorandom value.
182//config: You can reset the generator by using a specified start value.
183//config: After "unset RANDOM" the generator will switch off and this
184//config: variable will no longer have special treatment.
185//config:
186//config:config ASH_EXPAND_PRMT
187//config: bool "Expand prompt string"
188//config: default y
189//config: depends on ASH
190//config: help
191//config: "PS#" may contain volatile content, such as backquote commands.
192//config: This option recreates the prompt string from the environment
193//config: variable each time it is displayed.
Denys Vlasenko51ca7762010-07-16 17:16:40 +0200194//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200195
Denys Vlasenko20704f02011-03-23 17:59:27 +0100196//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
197//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
198//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
199
200//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
201//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
202
Denis Vlasenkob012b102007-02-19 22:43:01 +0000203
Denis Vlasenko01631112007-12-16 17:20:38 +0000204/* ============ Hash table sizes. Configurable. */
205
206#define VTABSIZE 39
207#define ATABSIZE 39
208#define CMDTABLESIZE 31 /* should be prime */
209
210
Denis Vlasenkob012b102007-02-19 22:43:01 +0000211/* ============ Shell options */
212
213static const char *const optletters_optnames[] = {
214 "e" "errexit",
215 "f" "noglob",
216 "I" "ignoreeof",
217 "i" "interactive",
218 "m" "monitor",
219 "n" "noexec",
220 "s" "stdin",
221 "x" "xtrace",
222 "v" "verbose",
223 "C" "noclobber",
224 "a" "allexport",
225 "b" "notify",
226 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100227 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100228#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100229 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100230#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000231#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000232 ,"\0" "nolog"
233 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000234#endif
235};
236
Denys Vlasenko285ad152009-12-04 23:02:27 +0100237#define optletters(n) optletters_optnames[n][0]
238#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000239
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000240enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000241
Eric Andersenc470f442003-07-28 09:56:35 +0000242
Denis Vlasenkob012b102007-02-19 22:43:01 +0000243/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000244
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200245#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000246
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000247/*
Eric Andersenc470f442003-07-28 09:56:35 +0000248 * We enclose jmp_buf in a structure so that we can declare pointers to
249 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000250 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000251 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000252 * exception handlers, the user should save the value of handler on entry
253 * to an inner scope, set handler to point to a jmploc structure for the
254 * inner scope, and restore handler on exit from the scope.
255 */
Eric Andersenc470f442003-07-28 09:56:35 +0000256struct jmploc {
257 jmp_buf loc;
258};
Denis Vlasenko01631112007-12-16 17:20:38 +0000259
260struct globals_misc {
261 /* pid of main shell */
262 int rootpid;
263 /* shell level: 0 for the main shell, 1 for its children, and so on */
264 int shlvl;
265#define rootshell (!shlvl)
266 char *minusc; /* argument to -c option */
267
268 char *curdir; // = nullstr; /* current working directory */
269 char *physdir; // = nullstr; /* physical working directory */
270
271 char *arg0; /* value of $0 */
272
273 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000274
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200275 volatile int suppress_int; /* counter */
276 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000277 /* last pending signal */
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200278 volatile /*sig_atomic_t*/ smallint pending_sig;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000279 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000280 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000281#define EXINT 0 /* SIGINT received */
282#define EXERROR 1 /* a generic error */
283#define EXSHELLPROC 2 /* execute a shell procedure */
284#define EXEXEC 3 /* command execution failed */
285#define EXEXIT 4 /* exit the shell */
286#define EXSIG 5 /* trapped signal in wait(1) */
Eric Andersen2870d962001-07-02 17:27:21 +0000287
Denis Vlasenko01631112007-12-16 17:20:38 +0000288 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000289 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000290
291 char optlist[NOPTS];
292#define eflag optlist[0]
293#define fflag optlist[1]
294#define Iflag optlist[2]
295#define iflag optlist[3]
296#define mflag optlist[4]
297#define nflag optlist[5]
298#define sflag optlist[6]
299#define xflag optlist[7]
300#define vflag optlist[8]
301#define Cflag optlist[9]
302#define aflag optlist[10]
303#define bflag optlist[11]
304#define uflag optlist[12]
305#define viflag optlist[13]
Michael Abbott359da5e2009-12-04 23:03:29 +0100306#if ENABLE_ASH_BASH_COMPAT
307# define pipefail optlist[14]
308#else
309# define pipefail 0
310#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000311#if DEBUG
Michael Abbott359da5e2009-12-04 23:03:29 +0100312# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
313# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000314#endif
315
316 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000317 /*
318 * Sigmode records the current value of the signal handlers for the various
319 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000320 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000321 */
322 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000323#define S_DFL 1 /* default signal handling (SIG_DFL) */
324#define S_CATCH 2 /* signal is caught */
325#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200326#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000327
Denis Vlasenko01631112007-12-16 17:20:38 +0000328 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000329 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200330 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000331 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200332 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000333
334 /* Rarely referenced stuff */
335#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200336 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000337#endif
338 pid_t backgndpid; /* pid of last background process */
339 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
Denis Vlasenko01631112007-12-16 17:20:38 +0000340};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000341extern struct globals_misc *const ash_ptr_to_globals_misc;
342#define G_misc (*ash_ptr_to_globals_misc)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000343#define rootpid (G_misc.rootpid )
344#define shlvl (G_misc.shlvl )
345#define minusc (G_misc.minusc )
346#define curdir (G_misc.curdir )
347#define physdir (G_misc.physdir )
348#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000349#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000350#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200351#define suppress_int (G_misc.suppress_int )
352#define pending_int (G_misc.pending_int )
353#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000354#define isloginsh (G_misc.isloginsh )
355#define nullstr (G_misc.nullstr )
356#define optlist (G_misc.optlist )
357#define sigmode (G_misc.sigmode )
358#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200359#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000360#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200361#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200362#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000363#define backgndpid (G_misc.backgndpid )
364#define job_warning (G_misc.job_warning)
Denis Vlasenko01631112007-12-16 17:20:38 +0000365#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000366 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
367 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000368 curdir = nullstr; \
369 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200370 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000371} while (0)
372
373
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000374/* ============ DEBUG */
375#if DEBUG
376static void trace_printf(const char *fmt, ...);
377static void trace_vprintf(const char *fmt, va_list va);
378# define TRACE(param) trace_printf param
379# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000380# define close(fd) do { \
381 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000382 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200383 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000384 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000385} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000386#else
387# define TRACE(param)
388# define TRACEV(param)
389#endif
390
391
Denis Vlasenko559691a2008-10-05 18:39:31 +0000392/* ============ Utility functions */
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000393#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
394
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100395#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
396#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
397
Denis Vlasenko559691a2008-10-05 18:39:31 +0000398static int isdigit_str9(const char *str)
399{
400 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
401 while (--maxlen && isdigit(*str))
402 str++;
403 return (*str == '\0');
404}
Denis Vlasenko01631112007-12-16 17:20:38 +0000405
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200406static const char *var_end(const char *var)
407{
408 while (*var)
409 if (*var++ == '=')
410 break;
411 return var;
412}
413
Denis Vlasenko559691a2008-10-05 18:39:31 +0000414
415/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100416
417static void exitshell(void) NORETURN;
418
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000419/*
Eric Andersen2870d962001-07-02 17:27:21 +0000420 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000421 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000422 * much more efficient and portable. (But hacking the kernel is so much
423 * more fun than worrying about efficiency and portability. :-))
424 */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000425#define INT_OFF do { \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200426 suppress_int++; \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000427 xbarrier(); \
428} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000429
430/*
431 * Called to raise an exception. Since C doesn't include exceptions, we
432 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000433 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000434 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000435static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000436static void
437raise_exception(int e)
438{
439#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000440 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000441 abort();
442#endif
443 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000444 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000445 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000446}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000447#if DEBUG
448#define raise_exception(e) do { \
449 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
450 raise_exception(e); \
451} while (0)
452#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000453
454/*
455 * Called from trap.c when a SIGINT is received. (If the user specifies
456 * that SIGINT is to be trapped or ignored using the trap builtin, then
457 * this routine is not called.) Suppressint is nonzero when interrupts
458 * are held using the INT_OFF macro. (The test for iflag is just
459 * defensive programming.)
460 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000461static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000462static void
463raise_interrupt(void)
464{
Denis Vlasenko4b875702009-03-19 13:30:04 +0000465 int ex_type;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000466
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200467 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000468 /* Signal is not automatically unmasked after it is raised,
469 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000470 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200471 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000472
Denis Vlasenko4b875702009-03-19 13:30:04 +0000473 ex_type = EXSIG;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000474 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
475 if (!(rootshell && iflag)) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000476 /* Kill ourself with SIGINT */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000477 signal(SIGINT, SIG_DFL);
478 raise(SIGINT);
479 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000480 ex_type = EXINT;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000481 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000482 raise_exception(ex_type);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000483 /* NOTREACHED */
484}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000485#if DEBUG
486#define raise_interrupt() do { \
487 TRACE(("raising interrupt on line %d\n", __LINE__)); \
488 raise_interrupt(); \
489} while (0)
490#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000491
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000492static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000493int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000494{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000495 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200496 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000497 raise_interrupt();
498 }
499}
500#define INT_ON int_on()
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000501static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000502force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000503{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000504 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200505 suppress_int = 0;
506 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000507 raise_interrupt();
508}
509#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000510
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200511#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000512
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000513#define RESTORE_INT(v) do { \
514 xbarrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200515 suppress_int = (v); \
516 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000517 raise_interrupt(); \
518} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000519
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000520
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000521/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000522
Eric Andersenc470f442003-07-28 09:56:35 +0000523static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000524outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000525{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000526 INT_OFF;
527 fputs(p, file);
528 INT_ON;
529}
530
531static void
532flush_stdout_stderr(void)
533{
534 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100535 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000536 INT_ON;
537}
538
Denys Vlasenko9c541002015-10-07 15:44:36 +0200539/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000540static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200541newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000542{
543 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200544 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000545 fflush(dest);
546 INT_ON;
547}
548
549static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
550static int
551out1fmt(const char *fmt, ...)
552{
553 va_list ap;
554 int r;
555
556 INT_OFF;
557 va_start(ap, fmt);
558 r = vprintf(fmt, ap);
559 va_end(ap);
560 INT_ON;
561 return r;
562}
563
564static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
565static int
566fmtstr(char *outbuf, size_t length, const char *fmt, ...)
567{
568 va_list ap;
569 int ret;
570
571 va_start(ap, fmt);
572 INT_OFF;
573 ret = vsnprintf(outbuf, length, fmt, ap);
574 va_end(ap);
575 INT_ON;
576 return ret;
577}
578
579static void
580out1str(const char *p)
581{
582 outstr(p, stdout);
583}
584
585static void
586out2str(const char *p)
587{
588 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100589 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000590}
591
592
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000593/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000594
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000595/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100596#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200597#define CTLESC ((unsigned char)'\201') /* escape next character */
598#define CTLVAR ((unsigned char)'\202') /* variable defn */
599#define CTLENDVAR ((unsigned char)'\203')
600#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200601#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
602#define CTLENDARI ((unsigned char)'\207')
603#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100604#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000605
606/* variable substitution byte (follows CTLVAR) */
607#define VSTYPE 0x0f /* type of variable substitution */
608#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000609
610/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000611#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
612#define VSMINUS 0x2 /* ${var-text} */
613#define VSPLUS 0x3 /* ${var+text} */
614#define VSQUESTION 0x4 /* ${var?message} */
615#define VSASSIGN 0x5 /* ${var=text} */
616#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
617#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
618#define VSTRIMLEFT 0x8 /* ${var#pattern} */
619#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
620#define VSLENGTH 0xa /* ${#var} */
621#if ENABLE_ASH_BASH_COMPAT
622#define VSSUBSTR 0xc /* ${var:position:length} */
623#define VSREPLACE 0xd /* ${var/pattern/replacement} */
624#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
625#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000626
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000627static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200628 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000629};
Ron Yorston549deab2015-05-18 09:57:51 +0200630#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000631
Denis Vlasenko559691a2008-10-05 18:39:31 +0000632#define NCMD 0
633#define NPIPE 1
634#define NREDIR 2
635#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000636#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000637#define NAND 5
638#define NOR 6
639#define NSEMI 7
640#define NIF 8
641#define NWHILE 9
642#define NUNTIL 10
643#define NFOR 11
644#define NCASE 12
645#define NCLIST 13
646#define NDEFUN 14
647#define NARG 15
648#define NTO 16
649#if ENABLE_ASH_BASH_COMPAT
650#define NTO2 17
651#endif
652#define NCLOBBER 18
653#define NFROM 19
654#define NFROMTO 20
655#define NAPPEND 21
656#define NTOFD 22
657#define NFROMFD 23
658#define NHERE 24
659#define NXHERE 25
660#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000661#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000662
663union node;
664
665struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000666 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000667 union node *assign;
668 union node *args;
669 union node *redirect;
670};
671
672struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000673 smallint type;
674 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000675 struct nodelist *cmdlist;
676};
677
678struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000679 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000680 union node *n;
681 union node *redirect;
682};
683
684struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000685 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000686 union node *ch1;
687 union node *ch2;
688};
689
690struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000691 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000692 union node *test;
693 union node *ifpart;
694 union node *elsepart;
695};
696
697struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000698 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000699 union node *args;
700 union node *body;
701 char *var;
702};
703
704struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000705 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000706 union node *expr;
707 union node *cases;
708};
709
710struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000711 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000712 union node *next;
713 union node *pattern;
714 union node *body;
715};
716
717struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000718 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000719 union node *next;
720 char *text;
721 struct nodelist *backquote;
722};
723
Denis Vlasenko559691a2008-10-05 18:39:31 +0000724/* nfile and ndup layout must match!
725 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
726 * that it is actually NTO2 (>&file), and change its type.
727 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000728struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000729 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000730 union node *next;
731 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000732 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000733 union node *fname;
734 char *expfname;
735};
736
737struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000738 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000739 union node *next;
740 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000741 int dupfd;
742 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000743 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000744};
745
746struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000747 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000748 union node *next;
749 int fd;
750 union node *doc;
751};
752
753struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000754 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000755 union node *com;
756};
757
758union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000759 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000760 struct ncmd ncmd;
761 struct npipe npipe;
762 struct nredir nredir;
763 struct nbinary nbinary;
764 struct nif nif;
765 struct nfor nfor;
766 struct ncase ncase;
767 struct nclist nclist;
768 struct narg narg;
769 struct nfile nfile;
770 struct ndup ndup;
771 struct nhere nhere;
772 struct nnot nnot;
773};
774
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200775/*
776 * NODE_EOF is returned by parsecmd when it encounters an end of file.
777 * It must be distinct from NULL.
778 */
779#define NODE_EOF ((union node *) -1L)
780
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000781struct nodelist {
782 struct nodelist *next;
783 union node *n;
784};
785
786struct funcnode {
787 int count;
788 union node n;
789};
790
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000791/*
792 * Free a parse tree.
793 */
794static void
795freefunc(struct funcnode *f)
796{
797 if (f && --f->count < 0)
798 free(f);
799}
800
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000801
802/* ============ Debugging output */
803
804#if DEBUG
805
806static FILE *tracefile;
807
808static void
809trace_printf(const char *fmt, ...)
810{
811 va_list va;
812
813 if (debug != 1)
814 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000815 if (DEBUG_TIME)
816 fprintf(tracefile, "%u ", (int) time(NULL));
817 if (DEBUG_PID)
818 fprintf(tracefile, "[%u] ", (int) getpid());
819 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200820 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000821 va_start(va, fmt);
822 vfprintf(tracefile, fmt, va);
823 va_end(va);
824}
825
826static void
827trace_vprintf(const char *fmt, va_list va)
828{
829 if (debug != 1)
830 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000831 if (DEBUG_TIME)
832 fprintf(tracefile, "%u ", (int) time(NULL));
833 if (DEBUG_PID)
834 fprintf(tracefile, "[%u] ", (int) getpid());
835 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200836 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000837 vfprintf(tracefile, fmt, va);
838}
839
840static void
841trace_puts(const char *s)
842{
843 if (debug != 1)
844 return;
845 fputs(s, tracefile);
846}
847
848static void
849trace_puts_quoted(char *s)
850{
851 char *p;
852 char c;
853
854 if (debug != 1)
855 return;
856 putc('"', tracefile);
857 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100858 switch ((unsigned char)*p) {
859 case '\n': c = 'n'; goto backslash;
860 case '\t': c = 't'; goto backslash;
861 case '\r': c = 'r'; goto backslash;
862 case '\"': c = '\"'; goto backslash;
863 case '\\': c = '\\'; goto backslash;
864 case CTLESC: c = 'e'; goto backslash;
865 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100866 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000867 backslash:
868 putc('\\', tracefile);
869 putc(c, tracefile);
870 break;
871 default:
872 if (*p >= ' ' && *p <= '~')
873 putc(*p, tracefile);
874 else {
875 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100876 putc((*p >> 6) & 03, tracefile);
877 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000878 putc(*p & 07, tracefile);
879 }
880 break;
881 }
882 }
883 putc('"', tracefile);
884}
885
886static void
887trace_puts_args(char **ap)
888{
889 if (debug != 1)
890 return;
891 if (!*ap)
892 return;
893 while (1) {
894 trace_puts_quoted(*ap);
895 if (!*++ap) {
896 putc('\n', tracefile);
897 break;
898 }
899 putc(' ', tracefile);
900 }
901}
902
903static void
904opentrace(void)
905{
906 char s[100];
907#ifdef O_APPEND
908 int flags;
909#endif
910
911 if (debug != 1) {
912 if (tracefile)
913 fflush(tracefile);
914 /* leave open because libedit might be using it */
915 return;
916 }
917 strcpy(s, "./trace");
918 if (tracefile) {
919 if (!freopen(s, "a", tracefile)) {
920 fprintf(stderr, "Can't re-open %s\n", s);
921 debug = 0;
922 return;
923 }
924 } else {
925 tracefile = fopen(s, "a");
926 if (tracefile == NULL) {
927 fprintf(stderr, "Can't open %s\n", s);
928 debug = 0;
929 return;
930 }
931 }
932#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000933 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000934 if (flags >= 0)
935 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
936#endif
937 setlinebuf(tracefile);
938 fputs("\nTracing started.\n", tracefile);
939}
940
941static void
942indent(int amount, char *pfx, FILE *fp)
943{
944 int i;
945
946 for (i = 0; i < amount; i++) {
947 if (pfx && i == amount - 1)
948 fputs(pfx, fp);
949 putc('\t', fp);
950 }
951}
952
953/* little circular references here... */
954static void shtree(union node *n, int ind, char *pfx, FILE *fp);
955
956static void
957sharg(union node *arg, FILE *fp)
958{
959 char *p;
960 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100961 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000962
963 if (arg->type != NARG) {
964 out1fmt("<node type %d>\n", arg->type);
965 abort();
966 }
967 bqlist = arg->narg.backquote;
968 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100969 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000970 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700971 p++;
972 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000973 break;
974 case CTLVAR:
975 putc('$', fp);
976 putc('{', fp);
977 subtype = *++p;
978 if (subtype == VSLENGTH)
979 putc('#', fp);
980
Dan Fandrich77d48722010-09-07 23:38:28 -0700981 while (*p != '=') {
982 putc(*p, fp);
983 p++;
984 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000985
986 if (subtype & VSNUL)
987 putc(':', fp);
988
989 switch (subtype & VSTYPE) {
990 case VSNORMAL:
991 putc('}', fp);
992 break;
993 case VSMINUS:
994 putc('-', fp);
995 break;
996 case VSPLUS:
997 putc('+', fp);
998 break;
999 case VSQUESTION:
1000 putc('?', fp);
1001 break;
1002 case VSASSIGN:
1003 putc('=', fp);
1004 break;
1005 case VSTRIMLEFT:
1006 putc('#', fp);
1007 break;
1008 case VSTRIMLEFTMAX:
1009 putc('#', fp);
1010 putc('#', fp);
1011 break;
1012 case VSTRIMRIGHT:
1013 putc('%', fp);
1014 break;
1015 case VSTRIMRIGHTMAX:
1016 putc('%', fp);
1017 putc('%', fp);
1018 break;
1019 case VSLENGTH:
1020 break;
1021 default:
1022 out1fmt("<subtype %d>", subtype);
1023 }
1024 break;
1025 case CTLENDVAR:
1026 putc('}', fp);
1027 break;
1028 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001029 putc('$', fp);
1030 putc('(', fp);
1031 shtree(bqlist->n, -1, NULL, fp);
1032 putc(')', fp);
1033 break;
1034 default:
1035 putc(*p, fp);
1036 break;
1037 }
1038 }
1039}
1040
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001041static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001042shcmd(union node *cmd, FILE *fp)
1043{
1044 union node *np;
1045 int first;
1046 const char *s;
1047 int dftfd;
1048
1049 first = 1;
1050 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001051 if (!first)
1052 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001053 sharg(np, fp);
1054 first = 0;
1055 }
1056 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001057 if (!first)
1058 putc(' ', fp);
1059 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001060 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001061 case NTO: s = ">>"+1; dftfd = 1; break;
1062 case NCLOBBER: s = ">|"; dftfd = 1; break;
1063 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001064#if ENABLE_ASH_BASH_COMPAT
1065 case NTO2:
1066#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001067 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001068 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001069 case NFROMFD: s = "<&"; break;
1070 case NFROMTO: s = "<>"; break;
1071 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001072 }
1073 if (np->nfile.fd != dftfd)
1074 fprintf(fp, "%d", np->nfile.fd);
1075 fputs(s, fp);
1076 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1077 fprintf(fp, "%d", np->ndup.dupfd);
1078 } else {
1079 sharg(np->nfile.fname, fp);
1080 }
1081 first = 0;
1082 }
1083}
1084
1085static void
1086shtree(union node *n, int ind, char *pfx, FILE *fp)
1087{
1088 struct nodelist *lp;
1089 const char *s;
1090
1091 if (n == NULL)
1092 return;
1093
1094 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001095
1096 if (n == NODE_EOF) {
1097 fputs("<EOF>", fp);
1098 return;
1099 }
1100
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001101 switch (n->type) {
1102 case NSEMI:
1103 s = "; ";
1104 goto binop;
1105 case NAND:
1106 s = " && ";
1107 goto binop;
1108 case NOR:
1109 s = " || ";
1110 binop:
1111 shtree(n->nbinary.ch1, ind, NULL, fp);
1112 /* if (ind < 0) */
1113 fputs(s, fp);
1114 shtree(n->nbinary.ch2, ind, NULL, fp);
1115 break;
1116 case NCMD:
1117 shcmd(n, fp);
1118 if (ind >= 0)
1119 putc('\n', fp);
1120 break;
1121 case NPIPE:
1122 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001123 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001124 if (lp->next)
1125 fputs(" | ", fp);
1126 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001127 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001128 fputs(" &", fp);
1129 if (ind >= 0)
1130 putc('\n', fp);
1131 break;
1132 default:
1133 fprintf(fp, "<node type %d>", n->type);
1134 if (ind >= 0)
1135 putc('\n', fp);
1136 break;
1137 }
1138}
1139
1140static void
1141showtree(union node *n)
1142{
1143 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001144 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001145}
1146
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001147#endif /* DEBUG */
1148
1149
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001150/* ============ Parser data */
1151
1152/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001153 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1154 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001155struct strlist {
1156 struct strlist *next;
1157 char *text;
1158};
1159
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001160struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001161
Denis Vlasenkob012b102007-02-19 22:43:01 +00001162struct strpush {
1163 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001164 char *prev_string;
1165 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001166#if ENABLE_ASH_ALIAS
1167 struct alias *ap; /* if push was associated with an alias */
1168#endif
1169 char *string; /* remember the string since it may change */
1170};
1171
1172struct parsefile {
1173 struct parsefile *prev; /* preceding file on stack */
1174 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001175 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001176 int left_in_line; /* number of chars left in this line */
1177 int left_in_buffer; /* number of chars left in this buffer past the line */
1178 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001179 char *buf; /* input buffer */
1180 struct strpush *strpush; /* for pushing strings at this level */
1181 struct strpush basestrpush; /* so pushing one is fast */
1182};
1183
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001184static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001185static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001186static int startlinno; /* line # where last token started */
1187static char *commandname; /* currently executing command */
1188static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001189static uint8_t exitstatus; /* exit status of last command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001190
1191
1192/* ============ Message printing */
1193
1194static void
1195ash_vmsg(const char *msg, va_list ap)
1196{
1197 fprintf(stderr, "%s: ", arg0);
1198 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001199 if (strcmp(arg0, commandname))
1200 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001201 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001202 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001203 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001204 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001205 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001206}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001207
1208/*
1209 * Exverror is called to raise the error exception. If the second argument
1210 * is not NULL then error prints an error message using printf style
1211 * formatting. It then raises the error exception.
1212 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001213static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001214static void
1215ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001216{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001217#if DEBUG
1218 if (msg) {
1219 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1220 TRACEV((msg, ap));
1221 TRACE(("\") pid=%d\n", getpid()));
1222 } else
1223 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1224 if (msg)
1225#endif
1226 ash_vmsg(msg, ap);
1227
1228 flush_stdout_stderr();
1229 raise_exception(cond);
1230 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001231}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001232
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001233static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001234static void
1235ash_msg_and_raise_error(const char *msg, ...)
1236{
1237 va_list ap;
1238
1239 va_start(ap, msg);
1240 ash_vmsg_and_raise(EXERROR, msg, ap);
1241 /* NOTREACHED */
1242 va_end(ap);
1243}
1244
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001245static void raise_error_syntax(const char *) NORETURN;
1246static void
1247raise_error_syntax(const char *msg)
1248{
1249 ash_msg_and_raise_error("syntax error: %s", msg);
1250 /* NOTREACHED */
1251}
1252
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001253static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001254static void
1255ash_msg_and_raise(int cond, const char *msg, ...)
1256{
1257 va_list ap;
1258
1259 va_start(ap, msg);
1260 ash_vmsg_and_raise(cond, msg, ap);
1261 /* NOTREACHED */
1262 va_end(ap);
1263}
1264
1265/*
1266 * error/warning routines for external builtins
1267 */
1268static void
1269ash_msg(const char *fmt, ...)
1270{
1271 va_list ap;
1272
1273 va_start(ap, fmt);
1274 ash_vmsg(fmt, ap);
1275 va_end(ap);
1276}
1277
1278/*
1279 * Return a string describing an error. The returned string may be a
1280 * pointer to a static buffer that will be overwritten on the next call.
1281 * Action describes the operation that got the error.
1282 */
1283static const char *
1284errmsg(int e, const char *em)
1285{
1286 if (e == ENOENT || e == ENOTDIR) {
1287 return em;
1288 }
1289 return strerror(e);
1290}
1291
1292
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001293/* ============ Memory allocation */
1294
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001295#if 0
1296/* I consider these wrappers nearly useless:
1297 * ok, they return you to nearest exception handler, but
1298 * how much memory do you leak in the process, making
1299 * memory starvation worse?
1300 */
1301static void *
1302ckrealloc(void * p, size_t nbytes)
1303{
1304 p = realloc(p, nbytes);
1305 if (!p)
1306 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1307 return p;
1308}
1309
1310static void *
1311ckmalloc(size_t nbytes)
1312{
1313 return ckrealloc(NULL, nbytes);
1314}
1315
1316static void *
1317ckzalloc(size_t nbytes)
1318{
1319 return memset(ckmalloc(nbytes), 0, nbytes);
1320}
1321
1322static char *
1323ckstrdup(const char *s)
1324{
1325 char *p = strdup(s);
1326 if (!p)
1327 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1328 return p;
1329}
1330#else
1331/* Using bbox equivalents. They exit if out of memory */
1332# define ckrealloc xrealloc
1333# define ckmalloc xmalloc
1334# define ckzalloc xzalloc
1335# define ckstrdup xstrdup
1336#endif
1337
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001338/*
1339 * It appears that grabstackstr() will barf with such alignments
1340 * because stalloc() will return a string allocated in a new stackblock.
1341 */
1342#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1343enum {
1344 /* Most machines require the value returned from malloc to be aligned
1345 * in some way. The following macro will get this right
1346 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001347 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001348 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001349 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001350};
1351
1352struct stack_block {
1353 struct stack_block *prev;
1354 char space[MINSIZE];
1355};
1356
1357struct stackmark {
1358 struct stack_block *stackp;
1359 char *stacknxt;
1360 size_t stacknleft;
1361 struct stackmark *marknext;
1362};
1363
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001364
Denis Vlasenko01631112007-12-16 17:20:38 +00001365struct globals_memstack {
1366 struct stack_block *g_stackp; // = &stackbase;
1367 struct stackmark *markp;
1368 char *g_stacknxt; // = stackbase.space;
1369 char *sstrend; // = stackbase.space + MINSIZE;
1370 size_t g_stacknleft; // = MINSIZE;
1371 int herefd; // = -1;
1372 struct stack_block stackbase;
1373};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001374extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1375#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001376#define g_stackp (G_memstack.g_stackp )
1377#define markp (G_memstack.markp )
1378#define g_stacknxt (G_memstack.g_stacknxt )
1379#define sstrend (G_memstack.sstrend )
1380#define g_stacknleft (G_memstack.g_stacknleft)
1381#define herefd (G_memstack.herefd )
1382#define stackbase (G_memstack.stackbase )
1383#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001384 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1385 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001386 g_stackp = &stackbase; \
1387 g_stacknxt = stackbase.space; \
1388 g_stacknleft = MINSIZE; \
1389 sstrend = stackbase.space + MINSIZE; \
1390 herefd = -1; \
1391} while (0)
1392
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001393
Denis Vlasenko01631112007-12-16 17:20:38 +00001394#define stackblock() ((void *)g_stacknxt)
1395#define stackblocksize() g_stacknleft
1396
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001397/*
1398 * Parse trees for commands are allocated in lifo order, so we use a stack
1399 * to make this more efficient, and also to avoid all sorts of exception
1400 * handling code to handle interrupts in the middle of a parse.
1401 *
1402 * The size 504 was chosen because the Ultrix malloc handles that size
1403 * well.
1404 */
1405static void *
1406stalloc(size_t nbytes)
1407{
1408 char *p;
1409 size_t aligned;
1410
1411 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001412 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001413 size_t len;
1414 size_t blocksize;
1415 struct stack_block *sp;
1416
1417 blocksize = aligned;
1418 if (blocksize < MINSIZE)
1419 blocksize = MINSIZE;
1420 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1421 if (len < blocksize)
1422 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1423 INT_OFF;
1424 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001425 sp->prev = g_stackp;
1426 g_stacknxt = sp->space;
1427 g_stacknleft = blocksize;
1428 sstrend = g_stacknxt + blocksize;
1429 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001430 INT_ON;
1431 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001432 p = g_stacknxt;
1433 g_stacknxt += aligned;
1434 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001435 return p;
1436}
1437
Denis Vlasenko597906c2008-02-20 16:38:54 +00001438static void *
1439stzalloc(size_t nbytes)
1440{
1441 return memset(stalloc(nbytes), 0, nbytes);
1442}
1443
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001444static void
1445stunalloc(void *p)
1446{
1447#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001448 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001449 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001450 abort();
1451 }
1452#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001453 g_stacknleft += g_stacknxt - (char *)p;
1454 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001455}
1456
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001457/*
1458 * Like strdup but works with the ash stack.
1459 */
1460static char *
1461ststrdup(const char *p)
1462{
1463 size_t len = strlen(p) + 1;
1464 return memcpy(stalloc(len), p, len);
1465}
1466
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001467static void
1468setstackmark(struct stackmark *mark)
1469{
Denis Vlasenko01631112007-12-16 17:20:38 +00001470 mark->stackp = g_stackp;
1471 mark->stacknxt = g_stacknxt;
1472 mark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001473 mark->marknext = markp;
1474 markp = mark;
1475}
1476
1477static void
1478popstackmark(struct stackmark *mark)
1479{
1480 struct stack_block *sp;
1481
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001482 if (!mark->stackp)
1483 return;
1484
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001485 INT_OFF;
1486 markp = mark->marknext;
Denis Vlasenko01631112007-12-16 17:20:38 +00001487 while (g_stackp != mark->stackp) {
1488 sp = g_stackp;
1489 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001490 free(sp);
1491 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001492 g_stacknxt = mark->stacknxt;
1493 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001494 sstrend = mark->stacknxt + mark->stacknleft;
1495 INT_ON;
1496}
1497
1498/*
1499 * When the parser reads in a string, it wants to stick the string on the
1500 * stack and only adjust the stack pointer when it knows how big the
1501 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1502 * of space on top of the stack and stackblocklen returns the length of
1503 * this block. Growstackblock will grow this space by at least one byte,
1504 * possibly moving it (like realloc). Grabstackblock actually allocates the
1505 * part of the block that has been used.
1506 */
1507static void
1508growstackblock(void)
1509{
1510 size_t newlen;
1511
Denis Vlasenko01631112007-12-16 17:20:38 +00001512 newlen = g_stacknleft * 2;
1513 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001514 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1515 if (newlen < 128)
1516 newlen += 128;
1517
Denis Vlasenko01631112007-12-16 17:20:38 +00001518 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001519 struct stack_block *oldstackp;
1520 struct stackmark *xmark;
1521 struct stack_block *sp;
1522 struct stack_block *prevstackp;
1523 size_t grosslen;
1524
1525 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001526 oldstackp = g_stackp;
1527 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001528 prevstackp = sp->prev;
1529 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1530 sp = ckrealloc(sp, grosslen);
1531 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001532 g_stackp = sp;
1533 g_stacknxt = sp->space;
1534 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001535 sstrend = sp->space + newlen;
1536
1537 /*
1538 * Stack marks pointing to the start of the old block
1539 * must be relocated to point to the new block
1540 */
1541 xmark = markp;
1542 while (xmark != NULL && xmark->stackp == oldstackp) {
Denis Vlasenko01631112007-12-16 17:20:38 +00001543 xmark->stackp = g_stackp;
1544 xmark->stacknxt = g_stacknxt;
1545 xmark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001546 xmark = xmark->marknext;
1547 }
1548 INT_ON;
1549 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001550 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001551 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001552 char *p = stalloc(newlen);
1553
1554 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001555 g_stacknxt = memcpy(p, oldspace, oldlen);
1556 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001557 }
1558}
1559
1560static void
1561grabstackblock(size_t len)
1562{
1563 len = SHELL_ALIGN(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001564 g_stacknxt += len;
1565 g_stacknleft -= len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001566}
1567
1568/*
1569 * The following routines are somewhat easier to use than the above.
1570 * The user declares a variable of type STACKSTR, which may be declared
1571 * to be a register. The macro STARTSTACKSTR initializes things. Then
1572 * the user uses the macro STPUTC to add characters to the string. In
1573 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1574 * grown as necessary. When the user is done, she can just leave the
1575 * string there and refer to it using stackblock(). Or she can allocate
1576 * the space for it using grabstackstr(). If it is necessary to allow
1577 * someone else to use the stack temporarily and then continue to grow
1578 * the string, the user should use grabstack to allocate the space, and
1579 * then call ungrabstr(p) to return to the previous mode of operation.
1580 *
1581 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1582 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1583 * is space for at least one character.
1584 */
1585static void *
1586growstackstr(void)
1587{
1588 size_t len = stackblocksize();
1589 if (herefd >= 0 && len >= 1024) {
1590 full_write(herefd, stackblock(), len);
1591 return stackblock();
1592 }
1593 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001594 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001595}
1596
1597/*
1598 * Called from CHECKSTRSPACE.
1599 */
1600static char *
1601makestrspace(size_t newlen, char *p)
1602{
Denis Vlasenko01631112007-12-16 17:20:38 +00001603 size_t len = p - g_stacknxt;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001604 size_t size = stackblocksize();
1605
1606 for (;;) {
1607 size_t nleft;
1608
1609 size = stackblocksize();
1610 nleft = size - len;
1611 if (nleft >= newlen)
1612 break;
1613 growstackblock();
1614 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001615 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001616}
1617
1618static char *
1619stack_nputstr(const char *s, size_t n, char *p)
1620{
1621 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001622 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001623 return p;
1624}
1625
1626static char *
1627stack_putstr(const char *s, char *p)
1628{
1629 return stack_nputstr(s, strlen(s), p);
1630}
1631
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001632static char *
1633_STPUTC(int c, char *p)
1634{
1635 if (p == sstrend)
1636 p = growstackstr();
1637 *p++ = c;
1638 return p;
1639}
1640
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001641#define STARTSTACKSTR(p) ((p) = stackblock())
1642#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001643#define CHECKSTRSPACE(n, p) do { \
1644 char *q = (p); \
1645 size_t l = (n); \
1646 size_t m = sstrend - q; \
1647 if (l > m) \
1648 (p) = makestrspace(l, q); \
1649} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001650#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001651#define STACKSTRNUL(p) do { \
1652 if ((p) == sstrend) \
1653 (p) = growstackstr(); \
1654 *(p) = '\0'; \
1655} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001656#define STUNPUTC(p) (--(p))
1657#define STTOPC(p) ((p)[-1])
1658#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001659
1660#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001661#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001662#define stackstrend() ((void *)sstrend)
1663
1664
1665/* ============ String helpers */
1666
1667/*
1668 * prefix -- see if pfx is a prefix of string.
1669 */
1670static char *
1671prefix(const char *string, const char *pfx)
1672{
1673 while (*pfx) {
1674 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001675 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001676 }
1677 return (char *) string;
1678}
1679
1680/*
1681 * Check for a valid number. This should be elsewhere.
1682 */
1683static int
1684is_number(const char *p)
1685{
1686 do {
1687 if (!isdigit(*p))
1688 return 0;
1689 } while (*++p != '\0');
1690 return 1;
1691}
1692
1693/*
1694 * Convert a string of digits to an integer, printing an error message on
1695 * failure.
1696 */
1697static int
1698number(const char *s)
1699{
1700 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001701 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001702 return atoi(s);
1703}
1704
1705/*
1706 * Produce a possibly single quoted string suitable as input to the shell.
1707 * The return string is allocated on the stack.
1708 */
1709static char *
1710single_quote(const char *s)
1711{
1712 char *p;
1713
1714 STARTSTACKSTR(p);
1715
1716 do {
1717 char *q;
1718 size_t len;
1719
1720 len = strchrnul(s, '\'') - s;
1721
1722 q = p = makestrspace(len + 3, p);
1723
1724 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001725 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001726 *q++ = '\'';
1727 s += len;
1728
1729 STADJUST(q - p, p);
1730
Denys Vlasenkocd716832009-11-28 22:14:02 +01001731 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001732 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001733 len = 0;
1734 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001735
1736 q = p = makestrspace(len + 3, p);
1737
1738 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001739 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001740 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001741
1742 STADJUST(q - p, p);
1743 } while (*s);
1744
Denys Vlasenkocd716832009-11-28 22:14:02 +01001745 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001746
1747 return stackblock();
1748}
1749
1750
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001751/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001752
1753static char **argptr; /* argument list for builtin commands */
1754static char *optionarg; /* set by nextopt (like getopt) */
1755static char *optptr; /* used by nextopt */
1756
1757/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001758 * XXX - should get rid of. Have all builtins use getopt(3).
1759 * The library getopt must have the BSD extension static variable
1760 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001761 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001762 * Standard option processing (a la getopt) for builtin routines.
1763 * The only argument that is passed to nextopt is the option string;
1764 * the other arguments are unnecessary. It returns the character,
1765 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001766 */
1767static int
1768nextopt(const char *optstring)
1769{
1770 char *p;
1771 const char *q;
1772 char c;
1773
1774 p = optptr;
1775 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001776 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001777 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001778 if (p == NULL)
1779 return '\0';
1780 if (*p != '-')
1781 return '\0';
1782 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001783 return '\0';
1784 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001785 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001786 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001787 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001788 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001789 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001790 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001791 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001792 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001793 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001794 if (*++q == ':')
1795 q++;
1796 }
1797 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001798 if (*p == '\0') {
1799 p = *argptr++;
1800 if (p == NULL)
1801 ash_msg_and_raise_error("no arg for -%c option", c);
1802 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001803 optionarg = p;
1804 p = NULL;
1805 }
1806 optptr = p;
1807 return c;
1808}
1809
1810
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001811/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001812
Denis Vlasenko01631112007-12-16 17:20:38 +00001813/*
1814 * The parsefile structure pointed to by the global variable parsefile
1815 * contains information about the current file being read.
1816 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001817struct shparam {
1818 int nparam; /* # of positional parameters (without $0) */
1819#if ENABLE_ASH_GETOPTS
1820 int optind; /* next parameter to be processed by getopts */
1821 int optoff; /* used by getopts */
1822#endif
1823 unsigned char malloced; /* if parameter list dynamically allocated */
1824 char **p; /* parameter list */
1825};
1826
1827/*
1828 * Free the list of positional parameters.
1829 */
1830static void
1831freeparam(volatile struct shparam *param)
1832{
Denis Vlasenko01631112007-12-16 17:20:38 +00001833 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001834 char **ap, **ap1;
1835 ap = ap1 = param->p;
1836 while (*ap)
1837 free(*ap++);
1838 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001839 }
1840}
1841
1842#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001843static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001844#endif
1845
1846struct var {
1847 struct var *next; /* next entry in hash list */
1848 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001849 const char *var_text; /* name=value */
1850 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001851 /* the variable gets set/unset */
1852};
1853
1854struct localvar {
1855 struct localvar *next; /* next local variable in list */
1856 struct var *vp; /* the variable that was made local */
1857 int flags; /* saved flags */
1858 const char *text; /* saved text */
1859};
1860
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001861/* flags */
1862#define VEXPORT 0x01 /* variable is exported */
1863#define VREADONLY 0x02 /* variable cannot be modified */
1864#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1865#define VTEXTFIXED 0x08 /* text is statically allocated */
1866#define VSTACK 0x10 /* text is allocated on the stack */
1867#define VUNSET 0x20 /* the variable is not set */
1868#define VNOFUNC 0x40 /* don't call the callback function */
1869#define VNOSET 0x80 /* do not set variable - just readonly test */
1870#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001871#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001872# define VDYNAMIC 0x200 /* dynamic variable */
1873#else
1874# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001875#endif
1876
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001877
Denis Vlasenko01631112007-12-16 17:20:38 +00001878/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001879#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001880static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001881change_lc_all(const char *value)
1882{
1883 if (value && *value != '\0')
1884 setlocale(LC_ALL, value);
1885}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001886static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001887change_lc_ctype(const char *value)
1888{
1889 if (value && *value != '\0')
1890 setlocale(LC_CTYPE, value);
1891}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001892#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001893#if ENABLE_ASH_MAIL
1894static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001895static void changemail(const char *var_value) FAST_FUNC;
1896#else
1897# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001898#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001899static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001900#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001901static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001902#endif
1903
Denis Vlasenko01631112007-12-16 17:20:38 +00001904static const struct {
1905 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001906 const char *var_text;
1907 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001908} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001909 /*
1910 * Note: VEXPORT would not work correctly here for NOFORK applets:
1911 * some environment strings may be constant.
1912 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001913 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001914#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001915 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1916 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001917#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001918 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1919 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1920 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1921 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001922#if ENABLE_ASH_GETOPTS
Denis Vlasenko01631112007-12-16 17:20:38 +00001923 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001924#endif
1925#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001926 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001927#endif
1928#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001929 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1930 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001931#endif
1932#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001933 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001934#endif
1935};
1936
Denis Vlasenko0b769642008-07-24 07:54:57 +00001937struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001938
1939struct globals_var {
1940 struct shparam shellparam; /* $@ current positional parameters */
1941 struct redirtab *redirlist;
1942 int g_nullredirs;
1943 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1944 struct var *vartab[VTABSIZE];
1945 struct var varinit[ARRAY_SIZE(varinit_data)];
1946};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001947extern struct globals_var *const ash_ptr_to_globals_var;
1948#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001949#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001950//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001951#define g_nullredirs (G_var.g_nullredirs )
1952#define preverrout_fd (G_var.preverrout_fd)
1953#define vartab (G_var.vartab )
1954#define varinit (G_var.varinit )
1955#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001956 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001957 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1958 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001959 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001960 varinit[i].flags = varinit_data[i].flags; \
1961 varinit[i].var_text = varinit_data[i].var_text; \
1962 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001963 } \
1964} while (0)
1965
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001966#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001967#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001968# define vmail (&vifs)[1]
1969# define vmpath (&vmail)[1]
1970# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001971#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001972# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001973#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001974#define vps1 (&vpath)[1]
1975#define vps2 (&vps1)[1]
1976#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001977#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001978# define voptind (&vps4)[1]
1979# if ENABLE_ASH_RANDOM_SUPPORT
1980# define vrandom (&voptind)[1]
1981# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001982#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001983# if ENABLE_ASH_RANDOM_SUPPORT
1984# define vrandom (&vps4)[1]
1985# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001986#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001987
1988/*
1989 * The following macros access the values of the above variables.
1990 * They have to skip over the name. They return the null string
1991 * for unset variables.
1992 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001993#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001994#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001995#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001996# define mailval() (vmail.var_text + 5)
1997# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001998# define mpathset() ((vmpath.flags & VUNSET) == 0)
1999#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002000#define pathval() (vpath.var_text + 5)
2001#define ps1val() (vps1.var_text + 4)
2002#define ps2val() (vps2.var_text + 4)
2003#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002004#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002005# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002006#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002007
Denis Vlasenko01631112007-12-16 17:20:38 +00002008#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002009static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002010getoptsreset(const char *value)
2011{
2012 shellparam.optind = number(value);
2013 shellparam.optoff = -1;
2014}
2015#endif
2016
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002017/*
2018 * Compares two strings up to the first = or '\0'. The first
2019 * string must be terminated by '='; the second may be terminated by
2020 * either '=' or '\0'.
2021 */
2022static int
2023varcmp(const char *p, const char *q)
2024{
2025 int c, d;
2026
2027 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002028 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002029 goto out;
2030 p++;
2031 q++;
2032 }
2033 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002034 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002035 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002036 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002037 out:
2038 return c - d;
2039}
2040
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002041/*
2042 * Find the appropriate entry in the hash table from the name.
2043 */
2044static struct var **
2045hashvar(const char *p)
2046{
2047 unsigned hashval;
2048
2049 hashval = ((unsigned char) *p) << 4;
2050 while (*p && *p != '=')
2051 hashval += (unsigned char) *p++;
2052 return &vartab[hashval % VTABSIZE];
2053}
2054
2055static int
2056vpcmp(const void *a, const void *b)
2057{
2058 return varcmp(*(const char **)a, *(const char **)b);
2059}
2060
2061/*
2062 * This routine initializes the builtin variables.
2063 */
2064static void
2065initvar(void)
2066{
2067 struct var *vp;
2068 struct var *end;
2069 struct var **vpp;
2070
2071 /*
2072 * PS1 depends on uid
2073 */
2074#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002075 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002076#else
2077 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002078 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002079#endif
2080 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002081 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002082 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002083 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002084 vp->next = *vpp;
2085 *vpp = vp;
2086 } while (++vp < end);
2087}
2088
2089static struct var **
2090findvar(struct var **vpp, const char *name)
2091{
2092 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002093 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002094 break;
2095 }
2096 }
2097 return vpp;
2098}
2099
2100/*
2101 * Find the value of a variable. Returns NULL if not set.
2102 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002103static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002104lookupvar(const char *name)
2105{
2106 struct var *v;
2107
2108 v = *findvar(hashvar(name), name);
2109 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002110#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002111 /*
2112 * Dynamic variables are implemented roughly the same way they are
2113 * in bash. Namely, they're "special" so long as they aren't unset.
2114 * As soon as they're unset, they're no longer dynamic, and dynamic
2115 * lookup will no longer happen at that point. -- PFM.
2116 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002117 if (v->flags & VDYNAMIC)
2118 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002119#endif
2120 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002121 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002122 }
2123 return NULL;
2124}
2125
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002126static void reinit_unicode_for_ash(void)
2127{
2128 /* Unicode support should be activated even if LANG is set
2129 * _during_ shell execution, not only if it was set when
2130 * shell was started. Therefore, re-check LANG every time:
2131 */
2132 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2133 || ENABLE_UNICODE_USING_LOCALE
2134 ) {
2135 const char *s = lookupvar("LC_ALL");
2136 if (!s) s = lookupvar("LC_CTYPE");
2137 if (!s) s = lookupvar("LANG");
2138 reinit_unicode(s);
2139 }
2140}
2141
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002142/*
2143 * Search the environment of a builtin command.
2144 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002145static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002146bltinlookup(const char *name)
2147{
2148 struct strlist *sp;
2149
2150 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002151 if (varcmp(sp->text, name) == 0)
2152 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002153 }
2154 return lookupvar(name);
2155}
2156
2157/*
2158 * Same as setvar except that the variable and value are passed in
2159 * the first argument as name=value. Since the first argument will
2160 * be actually stored in the table, it should not be a string that
2161 * will go away.
2162 * Called with interrupts off.
2163 */
2164static void
2165setvareq(char *s, int flags)
2166{
2167 struct var *vp, **vpp;
2168
2169 vpp = hashvar(s);
2170 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2171 vp = *findvar(vpp, s);
2172 if (vp) {
2173 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2174 const char *n;
2175
2176 if (flags & VNOSAVE)
2177 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002178 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002179 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2180 }
2181
2182 if (flags & VNOSET)
2183 return;
2184
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002185 if (vp->var_func && !(flags & VNOFUNC))
2186 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002187
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002188 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2189 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002190
2191 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2192 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002193 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002194 if (flags & VNOSET)
2195 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002196 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002197 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002198 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002199 *vpp = vp;
2200 }
2201 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2202 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002203 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002204 vp->flags = flags;
2205}
2206
2207/*
2208 * Set the value of a variable. The flags argument is ored with the
2209 * flags of the variable. If val is NULL, the variable is unset.
2210 */
2211static void
2212setvar(const char *name, const char *val, int flags)
2213{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002214 const char *q;
2215 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002216 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002217 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002218 size_t vallen;
2219
2220 q = endofname(name);
2221 p = strchrnul(q, '=');
2222 namelen = p - name;
2223 if (!namelen || p != q)
2224 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2225 vallen = 0;
2226 if (val == NULL) {
2227 flags |= VUNSET;
2228 } else {
2229 vallen = strlen(val);
2230 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002231
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002232 INT_OFF;
2233 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002234 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002235 if (val) {
2236 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002237 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002238 }
2239 *p = '\0';
2240 setvareq(nameeq, flags | VNOSAVE);
2241 INT_ON;
2242}
2243
Denys Vlasenko03dad222010-01-12 23:29:57 +01002244static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002245setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002246{
2247 setvar(name, val, 0);
2248}
2249
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002250#if ENABLE_ASH_GETOPTS
2251/*
2252 * Safe version of setvar, returns 1 on success 0 on failure.
2253 */
2254static int
2255setvarsafe(const char *name, const char *val, int flags)
2256{
2257 int err;
2258 volatile int saveint;
2259 struct jmploc *volatile savehandler = exception_handler;
2260 struct jmploc jmploc;
2261
2262 SAVE_INT(saveint);
2263 if (setjmp(jmploc.loc))
2264 err = 1;
2265 else {
2266 exception_handler = &jmploc;
2267 setvar(name, val, flags);
2268 err = 0;
2269 }
2270 exception_handler = savehandler;
2271 RESTORE_INT(saveint);
2272 return err;
2273}
2274#endif
2275
2276/*
2277 * Unset the specified variable.
2278 */
2279static int
2280unsetvar(const char *s)
2281{
2282 struct var **vpp;
2283 struct var *vp;
2284 int retval;
2285
2286 vpp = findvar(hashvar(s), s);
2287 vp = *vpp;
2288 retval = 2;
2289 if (vp) {
2290 int flags = vp->flags;
2291
2292 retval = 1;
2293 if (flags & VREADONLY)
2294 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002295#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002296 vp->flags &= ~VDYNAMIC;
2297#endif
2298 if (flags & VUNSET)
2299 goto ok;
2300 if ((flags & VSTRFIXED) == 0) {
2301 INT_OFF;
2302 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002303 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002304 *vpp = vp->next;
2305 free(vp);
2306 INT_ON;
2307 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002308 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002309 vp->flags &= ~VEXPORT;
2310 }
2311 ok:
2312 retval = 0;
2313 }
2314 out:
2315 return retval;
2316}
2317
2318/*
2319 * Process a linked list of variable assignments.
2320 */
2321static void
2322listsetvar(struct strlist *list_set_var, int flags)
2323{
2324 struct strlist *lp = list_set_var;
2325
2326 if (!lp)
2327 return;
2328 INT_OFF;
2329 do {
2330 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002331 lp = lp->next;
2332 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002333 INT_ON;
2334}
2335
2336/*
2337 * Generate a list of variables satisfying the given conditions.
2338 */
2339static char **
2340listvars(int on, int off, char ***end)
2341{
2342 struct var **vpp;
2343 struct var *vp;
2344 char **ep;
2345 int mask;
2346
2347 STARTSTACKSTR(ep);
2348 vpp = vartab;
2349 mask = on | off;
2350 do {
2351 for (vp = *vpp; vp; vp = vp->next) {
2352 if ((vp->flags & mask) == on) {
2353 if (ep == stackstrend())
2354 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002355 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002356 }
2357 }
2358 } while (++vpp < vartab + VTABSIZE);
2359 if (ep == stackstrend())
2360 ep = growstackstr();
2361 if (end)
2362 *end = ep;
2363 *ep++ = NULL;
2364 return grabstackstr(ep);
2365}
2366
2367
2368/* ============ Path search helper
2369 *
2370 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002371 * of the path before the first call; path_advance will update
2372 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002373 * the possible path expansions in sequence. If an option (indicated by
2374 * a percent sign) appears in the path entry then the global variable
2375 * pathopt will be set to point to it; otherwise pathopt will be set to
2376 * NULL.
2377 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002378static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002379
2380static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002381path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002382{
2383 const char *p;
2384 char *q;
2385 const char *start;
2386 size_t len;
2387
2388 if (*path == NULL)
2389 return NULL;
2390 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002391 for (p = start; *p && *p != ':' && *p != '%'; p++)
2392 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002393 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2394 while (stackblocksize() < len)
2395 growstackblock();
2396 q = stackblock();
2397 if (p != start) {
2398 memcpy(q, start, p - start);
2399 q += p - start;
2400 *q++ = '/';
2401 }
2402 strcpy(q, name);
2403 pathopt = NULL;
2404 if (*p == '%') {
2405 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002406 while (*p && *p != ':')
2407 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002408 }
2409 if (*p == ':')
2410 *path = p + 1;
2411 else
2412 *path = NULL;
2413 return stalloc(len);
2414}
2415
2416
2417/* ============ Prompt */
2418
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002419static smallint doprompt; /* if set, prompt the user */
2420static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002421
2422#if ENABLE_FEATURE_EDITING
2423static line_input_t *line_input_state;
2424static const char *cmdedit_prompt;
2425static void
2426putprompt(const char *s)
2427{
2428 if (ENABLE_ASH_EXPAND_PRMT) {
2429 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002430 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002431 return;
2432 }
2433 cmdedit_prompt = s;
2434}
2435#else
2436static void
2437putprompt(const char *s)
2438{
2439 out2str(s);
2440}
2441#endif
2442
2443#if ENABLE_ASH_EXPAND_PRMT
2444/* expandstr() needs parsing machinery, so it is far away ahead... */
2445static const char *expandstr(const char *ps);
2446#else
2447#define expandstr(s) s
2448#endif
2449
2450static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002451setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002452{
2453 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002454 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2455
2456 if (!do_set)
2457 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002458
2459 needprompt = 0;
2460
2461 switch (whichprompt) {
2462 case 1:
2463 prompt = ps1val();
2464 break;
2465 case 2:
2466 prompt = ps2val();
2467 break;
2468 default: /* 0 */
2469 prompt = nullstr;
2470 }
2471#if ENABLE_ASH_EXPAND_PRMT
2472 setstackmark(&smark);
2473 stalloc(stackblocksize());
2474#endif
2475 putprompt(expandstr(prompt));
2476#if ENABLE_ASH_EXPAND_PRMT
2477 popstackmark(&smark);
2478#endif
2479}
2480
2481
2482/* ============ The cd and pwd commands */
2483
2484#define CD_PHYSICAL 1
2485#define CD_PRINT 2
2486
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002487static int
2488cdopt(void)
2489{
2490 int flags = 0;
2491 int i, j;
2492
2493 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002494 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002495 if (i != j) {
2496 flags ^= CD_PHYSICAL;
2497 j = i;
2498 }
2499 }
2500
2501 return flags;
2502}
2503
2504/*
2505 * Update curdir (the name of the current directory) in response to a
2506 * cd command.
2507 */
2508static const char *
2509updatepwd(const char *dir)
2510{
2511 char *new;
2512 char *p;
2513 char *cdcomppath;
2514 const char *lim;
2515
2516 cdcomppath = ststrdup(dir);
2517 STARTSTACKSTR(new);
2518 if (*dir != '/') {
2519 if (curdir == nullstr)
2520 return 0;
2521 new = stack_putstr(curdir, new);
2522 }
2523 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002524 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002525 if (*dir != '/') {
2526 if (new[-1] != '/')
2527 USTPUTC('/', new);
2528 if (new > lim && *lim == '/')
2529 lim++;
2530 } else {
2531 USTPUTC('/', new);
2532 cdcomppath++;
2533 if (dir[1] == '/' && dir[2] != '/') {
2534 USTPUTC('/', new);
2535 cdcomppath++;
2536 lim++;
2537 }
2538 }
2539 p = strtok(cdcomppath, "/");
2540 while (p) {
2541 switch (*p) {
2542 case '.':
2543 if (p[1] == '.' && p[2] == '\0') {
2544 while (new > lim) {
2545 STUNPUTC(new);
2546 if (new[-1] == '/')
2547 break;
2548 }
2549 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002550 }
2551 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002552 break;
2553 /* fall through */
2554 default:
2555 new = stack_putstr(p, new);
2556 USTPUTC('/', new);
2557 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002558 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002559 }
2560 if (new > lim)
2561 STUNPUTC(new);
2562 *new = 0;
2563 return stackblock();
2564}
2565
2566/*
2567 * Find out what the current directory is. If we already know the current
2568 * directory, this routine returns immediately.
2569 */
2570static char *
2571getpwd(void)
2572{
Denis Vlasenko01631112007-12-16 17:20:38 +00002573 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002574 return dir ? dir : nullstr;
2575}
2576
2577static void
2578setpwd(const char *val, int setold)
2579{
2580 char *oldcur, *dir;
2581
2582 oldcur = dir = curdir;
2583
2584 if (setold) {
2585 setvar("OLDPWD", oldcur, VEXPORT);
2586 }
2587 INT_OFF;
2588 if (physdir != nullstr) {
2589 if (physdir != oldcur)
2590 free(physdir);
2591 physdir = nullstr;
2592 }
2593 if (oldcur == val || !val) {
2594 char *s = getpwd();
2595 physdir = s;
2596 if (!val)
2597 dir = s;
2598 } else
2599 dir = ckstrdup(val);
2600 if (oldcur != dir && oldcur != nullstr) {
2601 free(oldcur);
2602 }
2603 curdir = dir;
2604 INT_ON;
2605 setvar("PWD", dir, VEXPORT);
2606}
2607
2608static void hashcd(void);
2609
2610/*
2611 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2612 * know that the current directory has changed.
2613 */
2614static int
2615docd(const char *dest, int flags)
2616{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002617 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002618 int err;
2619
2620 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2621
2622 INT_OFF;
2623 if (!(flags & CD_PHYSICAL)) {
2624 dir = updatepwd(dest);
2625 if (dir)
2626 dest = dir;
2627 }
2628 err = chdir(dest);
2629 if (err)
2630 goto out;
2631 setpwd(dir, 1);
2632 hashcd();
2633 out:
2634 INT_ON;
2635 return err;
2636}
2637
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002638static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002639cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002640{
2641 const char *dest;
2642 const char *path;
2643 const char *p;
2644 char c;
2645 struct stat statb;
2646 int flags;
2647
2648 flags = cdopt();
2649 dest = *argptr;
2650 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002651 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002652 else if (LONE_DASH(dest)) {
2653 dest = bltinlookup("OLDPWD");
2654 flags |= CD_PRINT;
2655 }
2656 if (!dest)
2657 dest = nullstr;
2658 if (*dest == '/')
2659 goto step7;
2660 if (*dest == '.') {
2661 c = dest[1];
2662 dotdot:
2663 switch (c) {
2664 case '\0':
2665 case '/':
2666 goto step6;
2667 case '.':
2668 c = dest[2];
2669 if (c != '.')
2670 goto dotdot;
2671 }
2672 }
2673 if (!*dest)
2674 dest = ".";
2675 path = bltinlookup("CDPATH");
2676 if (!path) {
2677 step6:
2678 step7:
2679 p = dest;
2680 goto docd;
2681 }
2682 do {
2683 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002684 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002685 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2686 if (c && c != ':')
2687 flags |= CD_PRINT;
2688 docd:
2689 if (!docd(p, flags))
2690 goto out;
2691 break;
2692 }
2693 } while (path);
2694 ash_msg_and_raise_error("can't cd to %s", dest);
2695 /* NOTREACHED */
2696 out:
2697 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002698 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002699 return 0;
2700}
2701
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002702static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002703pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002704{
2705 int flags;
2706 const char *dir = curdir;
2707
2708 flags = cdopt();
2709 if (flags) {
2710 if (physdir == nullstr)
2711 setpwd(dir, 0);
2712 dir = physdir;
2713 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002714 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002715 return 0;
2716}
2717
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002718
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002719/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002720
Denis Vlasenko834dee72008-10-07 09:18:30 +00002721
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002722#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002723
Eric Andersenc470f442003-07-28 09:56:35 +00002724/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002725#define CWORD 0 /* character is nothing special */
2726#define CNL 1 /* newline character */
2727#define CBACK 2 /* a backslash character */
2728#define CSQUOTE 3 /* single quote */
2729#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002730#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002731#define CBQUOTE 6 /* backwards single quote */
2732#define CVAR 7 /* a dollar sign */
2733#define CENDVAR 8 /* a '}' character */
2734#define CLP 9 /* a left paren in arithmetic */
2735#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002736#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002737#define CCTL 12 /* like CWORD, except it must be escaped */
2738#define CSPCL 13 /* these terminate a word */
2739#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002740
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002741#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002742#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002743# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002744#endif
2745
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002746#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002747
Mike Frysinger98c52642009-04-02 10:02:37 +00002748#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002749# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002750#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002751# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002752#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002753static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002754#if ENABLE_ASH_ALIAS
2755 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2756#endif
2757 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2758 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2759 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2760 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2761 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2762 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2763 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2764 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2765 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2766 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2767 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002768#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002769 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2770 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2771 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2772#endif
2773#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002774};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002775/* Constants below must match table above */
2776enum {
2777#if ENABLE_ASH_ALIAS
2778 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2779#endif
2780 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2781 CNL_CNL_CNL_CNL , /* 2 */
2782 CWORD_CCTL_CCTL_CWORD , /* 3 */
2783 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2784 CVAR_CVAR_CWORD_CVAR , /* 5 */
2785 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2786 CSPCL_CWORD_CWORD_CLP , /* 7 */
2787 CSPCL_CWORD_CWORD_CRP , /* 8 */
2788 CBACK_CBACK_CCTL_CBACK , /* 9 */
2789 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2790 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2791 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2792 CWORD_CWORD_CWORD_CWORD , /* 13 */
2793 CCTL_CCTL_CCTL_CCTL , /* 14 */
2794};
Eric Andersen2870d962001-07-02 17:27:21 +00002795
Denys Vlasenkocd716832009-11-28 22:14:02 +01002796/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2797 * caller must ensure proper cast on it if c is *char_ptr!
2798 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002799/* Values for syntax param */
2800#define BASESYNTAX 0 /* not in quotes */
2801#define DQSYNTAX 1 /* in double quotes */
2802#define SQSYNTAX 2 /* in single quotes */
2803#define ARISYNTAX 3 /* in arithmetic */
2804#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002805
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002806#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002807
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002808static int
2809SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002810{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00002811 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Denys Vlasenkocd716832009-11-28 22:14:02 +01002812# if ENABLE_ASH_ALIAS
2813 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002814 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2815 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2816 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2817 11, 3 /* "}~" */
2818 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002819# else
2820 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002821 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2822 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2823 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2824 10, 2 /* "}~" */
2825 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002826# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002827 const char *s;
2828 int indx;
2829
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002830 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002831 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002832# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002833 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002834 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002835 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002836# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002837 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002838 /* Cast is purely for paranoia here,
2839 * just in case someone passed signed char to us */
2840 if ((unsigned char)c >= CTL_FIRST
2841 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002842 ) {
2843 return CCTL;
2844 }
2845 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002846 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002847 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002848 indx = syntax_index_table[s - spec_symbls];
2849 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002850 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002851}
2852
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002853#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002854
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002855static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002856 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002857 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2867 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2868 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2890 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2891 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2892 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2893 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2894 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2895 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2896 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2897 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2898 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2899 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2900 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2901 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2902 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2903 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2904 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2905 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2916 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2917 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2918 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2919 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2920 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2921 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2949 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2950 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2951 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2954 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2982 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2983 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2984 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2985 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2986 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2987 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2988 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2989 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2990 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2991 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2992 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2993 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2994 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2995 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 141 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003113 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003114# if ENABLE_ASH_ALIAS
3115 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3116# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003117};
3118
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003119# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003120
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003121#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003122
Eric Andersen2870d962001-07-02 17:27:21 +00003123
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003124/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003125
Denis Vlasenko131ae172007-02-18 13:00:19 +00003126#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003127
3128#define ALIASINUSE 1
3129#define ALIASDEAD 2
3130
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003131struct alias {
3132 struct alias *next;
3133 char *name;
3134 char *val;
3135 int flag;
3136};
3137
Denis Vlasenko01631112007-12-16 17:20:38 +00003138
3139static struct alias **atab; // [ATABSIZE];
3140#define INIT_G_alias() do { \
3141 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3142} while (0)
3143
Eric Andersen2870d962001-07-02 17:27:21 +00003144
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003145static struct alias **
3146__lookupalias(const char *name) {
3147 unsigned int hashval;
3148 struct alias **app;
3149 const char *p;
3150 unsigned int ch;
3151
3152 p = name;
3153
3154 ch = (unsigned char)*p;
3155 hashval = ch << 4;
3156 while (ch) {
3157 hashval += ch;
3158 ch = (unsigned char)*++p;
3159 }
3160 app = &atab[hashval % ATABSIZE];
3161
3162 for (; *app; app = &(*app)->next) {
3163 if (strcmp(name, (*app)->name) == 0) {
3164 break;
3165 }
3166 }
3167
3168 return app;
3169}
3170
3171static struct alias *
3172lookupalias(const char *name, int check)
3173{
3174 struct alias *ap = *__lookupalias(name);
3175
3176 if (check && ap && (ap->flag & ALIASINUSE))
3177 return NULL;
3178 return ap;
3179}
3180
3181static struct alias *
3182freealias(struct alias *ap)
3183{
3184 struct alias *next;
3185
3186 if (ap->flag & ALIASINUSE) {
3187 ap->flag |= ALIASDEAD;
3188 return ap;
3189 }
3190
3191 next = ap->next;
3192 free(ap->name);
3193 free(ap->val);
3194 free(ap);
3195 return next;
3196}
Eric Andersencb57d552001-06-28 07:25:16 +00003197
Eric Andersenc470f442003-07-28 09:56:35 +00003198static void
3199setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003200{
3201 struct alias *ap, **app;
3202
3203 app = __lookupalias(name);
3204 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003205 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003206 if (ap) {
3207 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003208 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003209 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003210 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003211 ap->flag &= ~ALIASDEAD;
3212 } else {
3213 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003214 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003215 ap->name = ckstrdup(name);
3216 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003217 /*ap->flag = 0; - ckzalloc did it */
3218 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003219 *app = ap;
3220 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003221 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003222}
3223
Eric Andersenc470f442003-07-28 09:56:35 +00003224static int
3225unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003226{
Eric Andersencb57d552001-06-28 07:25:16 +00003227 struct alias **app;
3228
3229 app = __lookupalias(name);
3230
3231 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003232 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003233 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003234 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003235 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003236 }
3237
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003238 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003239}
3240
Eric Andersenc470f442003-07-28 09:56:35 +00003241static void
3242rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003243{
Eric Andersencb57d552001-06-28 07:25:16 +00003244 struct alias *ap, **app;
3245 int i;
3246
Denis Vlasenkob012b102007-02-19 22:43:01 +00003247 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003248 for (i = 0; i < ATABSIZE; i++) {
3249 app = &atab[i];
3250 for (ap = *app; ap; ap = *app) {
3251 *app = freealias(*app);
3252 if (ap == *app) {
3253 app = &ap->next;
3254 }
3255 }
3256 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003257 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003258}
3259
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003260static void
3261printalias(const struct alias *ap)
3262{
3263 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3264}
3265
Eric Andersencb57d552001-06-28 07:25:16 +00003266/*
3267 * TODO - sort output
3268 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003269static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003270aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003271{
3272 char *n, *v;
3273 int ret = 0;
3274 struct alias *ap;
3275
Denis Vlasenko68404f12008-03-17 09:00:54 +00003276 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003277 int i;
3278
Denis Vlasenko68404f12008-03-17 09:00:54 +00003279 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003280 for (ap = atab[i]; ap; ap = ap->next) {
3281 printalias(ap);
3282 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003283 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003284 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003285 }
3286 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003287 v = strchr(n+1, '=');
3288 if (v == NULL) { /* n+1: funny ksh stuff */
3289 ap = *__lookupalias(n);
3290 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003291 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003292 ret = 1;
3293 } else
3294 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003295 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003296 *v++ = '\0';
3297 setalias(n, v);
3298 }
3299 }
3300
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003301 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003302}
3303
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003304static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003305unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003306{
3307 int i;
3308
3309 while ((i = nextopt("a")) != '\0') {
3310 if (i == 'a') {
3311 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003312 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003313 }
3314 }
3315 for (i = 0; *argptr; argptr++) {
3316 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003317 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003318 i = 1;
3319 }
3320 }
3321
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003322 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003323}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003324
Denis Vlasenko131ae172007-02-18 13:00:19 +00003325#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003326
Eric Andersenc470f442003-07-28 09:56:35 +00003327
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003328/* ============ jobs.c */
3329
3330/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003331#define FORK_FG 0
3332#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003333#define FORK_NOJOB 2
3334
3335/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003336#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3337#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3338#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003339#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003340
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003341/*
3342 * A job structure contains information about a job. A job is either a
3343 * single process or a set of processes contained in a pipeline. In the
3344 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3345 * array of pids.
3346 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003347struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003348 pid_t ps_pid; /* process id */
3349 int ps_status; /* last process status from wait() */
3350 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003351};
3352
3353struct job {
3354 struct procstat ps0; /* status of process */
3355 struct procstat *ps; /* status or processes when more than one */
3356#if JOBS
3357 int stopstatus; /* status of a stopped job */
3358#endif
3359 uint32_t
3360 nprocs: 16, /* number of processes */
3361 state: 8,
3362#define JOBRUNNING 0 /* at least one proc running */
3363#define JOBSTOPPED 1 /* all procs are stopped */
3364#define JOBDONE 2 /* all procs are completed */
3365#if JOBS
3366 sigint: 1, /* job was killed by SIGINT */
3367 jobctl: 1, /* job running under job control */
3368#endif
3369 waited: 1, /* true if this entry has been waited for */
3370 used: 1, /* true if this entry is in used */
3371 changed: 1; /* true if status has changed */
3372 struct job *prev_job; /* previous job */
3373};
3374
Denis Vlasenko68404f12008-03-17 09:00:54 +00003375static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003376static int forkshell(struct job *, union node *, int);
3377static int waitforjob(struct job *);
3378
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003379#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003380enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003381#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003382#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003383static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003384static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003385#endif
3386
3387/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003388 * Ignore a signal.
3389 */
3390static void
3391ignoresig(int signo)
3392{
3393 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3394 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3395 /* No, need to do it */
3396 signal(signo, SIG_IGN);
3397 }
3398 sigmode[signo - 1] = S_HARD_IGN;
3399}
3400
3401/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003402 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003403 */
3404static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003405signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003406{
3407 gotsig[signo - 1] = 1;
3408
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003409 if (signo == SIGINT && !trap[SIGINT]) {
3410 if (!suppress_int) {
3411 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003412 raise_interrupt(); /* does not return */
3413 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003414 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003415 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003416 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003417 }
3418}
3419
3420/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003421 * Set the signal handler for the specified signal. The routine figures
3422 * out what it should be set to.
3423 */
3424static void
3425setsignal(int signo)
3426{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003427 char *t;
3428 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003429 struct sigaction act;
3430
3431 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003432 new_act = S_DFL;
3433 if (t != NULL) { /* trap for this sig is set */
3434 new_act = S_CATCH;
3435 if (t[0] == '\0') /* trap is "": ignore this sig */
3436 new_act = S_IGN;
3437 }
3438
3439 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003440 switch (signo) {
3441 case SIGINT:
3442 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003443 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003444 break;
3445 case SIGQUIT:
3446#if DEBUG
3447 if (debug)
3448 break;
3449#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003450 /* man bash:
3451 * "In all cases, bash ignores SIGQUIT. Non-builtin
3452 * commands run by bash have signal handlers
3453 * set to the values inherited by the shell
3454 * from its parent". */
3455 new_act = S_IGN;
3456 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003457 case SIGTERM:
3458 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003459 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003460 break;
3461#if JOBS
3462 case SIGTSTP:
3463 case SIGTTOU:
3464 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003465 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003466 break;
3467#endif
3468 }
3469 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003470//TODO: if !rootshell, we reset SIGQUIT to DFL,
3471//whereas we have to restore it to what shell got on entry
3472//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003473
3474 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003475 cur_act = *t;
3476 if (cur_act == 0) {
3477 /* current setting is not yet known */
3478 if (sigaction(signo, NULL, &act)) {
3479 /* pretend it worked; maybe we should give a warning,
3480 * but other shells don't. We don't alter sigmode,
3481 * so we retry every time.
3482 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003483 return;
3484 }
3485 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003486 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003487 if (mflag
3488 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3489 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003490 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003491 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003492 }
3493 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003494 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003495 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003496
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003497 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003498 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003499 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003500 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003501 break;
3502 case S_IGN:
3503 act.sa_handler = SIG_IGN;
3504 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003505 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003506
3507 /* flags and mask matter only if !DFL and !IGN, but we do it
3508 * for all cases for more deterministic behavior:
3509 */
3510 act.sa_flags = 0;
3511 sigfillset(&act.sa_mask);
3512
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003513 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003514
3515 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003516}
3517
3518/* mode flags for set_curjob */
3519#define CUR_DELETE 2
3520#define CUR_RUNNING 1
3521#define CUR_STOPPED 0
3522
3523/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003524#define DOWAIT_NONBLOCK WNOHANG
3525#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003526
3527#if JOBS
3528/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003529static int initialpgrp; //references:2
3530static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003531#endif
3532/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003533static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003534/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003535static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003536/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003537static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003538/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003539static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003540
3541static void
3542set_curjob(struct job *jp, unsigned mode)
3543{
3544 struct job *jp1;
3545 struct job **jpp, **curp;
3546
3547 /* first remove from list */
3548 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003549 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003550 jp1 = *jpp;
3551 if (jp1 == jp)
3552 break;
3553 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003554 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003555 *jpp = jp1->prev_job;
3556
3557 /* Then re-insert in correct position */
3558 jpp = curp;
3559 switch (mode) {
3560 default:
3561#if DEBUG
3562 abort();
3563#endif
3564 case CUR_DELETE:
3565 /* job being deleted */
3566 break;
3567 case CUR_RUNNING:
3568 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003569 * put after all stopped jobs.
3570 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003571 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003572 jp1 = *jpp;
3573#if JOBS
3574 if (!jp1 || jp1->state != JOBSTOPPED)
3575#endif
3576 break;
3577 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003578 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003579 /* FALLTHROUGH */
3580#if JOBS
3581 case CUR_STOPPED:
3582#endif
3583 /* newly stopped job - becomes curjob */
3584 jp->prev_job = *jpp;
3585 *jpp = jp;
3586 break;
3587 }
3588}
3589
3590#if JOBS || DEBUG
3591static int
3592jobno(const struct job *jp)
3593{
3594 return jp - jobtab + 1;
3595}
3596#endif
3597
3598/*
3599 * Convert a job name to a job structure.
3600 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003601#if !JOBS
3602#define getjob(name, getctl) getjob(name)
3603#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003604static struct job *
3605getjob(const char *name, int getctl)
3606{
3607 struct job *jp;
3608 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003609 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003610 unsigned num;
3611 int c;
3612 const char *p;
3613 char *(*match)(const char *, const char *);
3614
3615 jp = curjob;
3616 p = name;
3617 if (!p)
3618 goto currentjob;
3619
3620 if (*p != '%')
3621 goto err;
3622
3623 c = *++p;
3624 if (!c)
3625 goto currentjob;
3626
3627 if (!p[1]) {
3628 if (c == '+' || c == '%') {
3629 currentjob:
3630 err_msg = "No current job";
3631 goto check;
3632 }
3633 if (c == '-') {
3634 if (jp)
3635 jp = jp->prev_job;
3636 err_msg = "No previous job";
3637 check:
3638 if (!jp)
3639 goto err;
3640 goto gotit;
3641 }
3642 }
3643
3644 if (is_number(p)) {
3645 num = atoi(p);
Denys Vlasenko07f7ea72014-09-08 17:21:52 +02003646 if (num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003647 jp = jobtab + num - 1;
3648 if (jp->used)
3649 goto gotit;
3650 goto err;
3651 }
3652 }
3653
3654 match = prefix;
3655 if (*p == '?') {
3656 match = strstr;
3657 p++;
3658 }
3659
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003660 found = NULL;
3661 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003662 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003663 if (found)
3664 goto err;
3665 found = jp;
3666 err_msg = "%s: ambiguous";
3667 }
3668 jp = jp->prev_job;
3669 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003670 if (!found)
3671 goto err;
3672 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003673
3674 gotit:
3675#if JOBS
3676 err_msg = "job %s not created under job control";
3677 if (getctl && jp->jobctl == 0)
3678 goto err;
3679#endif
3680 return jp;
3681 err:
3682 ash_msg_and_raise_error(err_msg, name);
3683}
3684
3685/*
3686 * Mark a job structure as unused.
3687 */
3688static void
3689freejob(struct job *jp)
3690{
3691 struct procstat *ps;
3692 int i;
3693
3694 INT_OFF;
3695 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003696 if (ps->ps_cmd != nullstr)
3697 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003698 }
3699 if (jp->ps != &jp->ps0)
3700 free(jp->ps);
3701 jp->used = 0;
3702 set_curjob(jp, CUR_DELETE);
3703 INT_ON;
3704}
3705
3706#if JOBS
3707static void
3708xtcsetpgrp(int fd, pid_t pgrp)
3709{
3710 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003711 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003712}
3713
3714/*
3715 * Turn job control on and off.
3716 *
3717 * Note: This code assumes that the third arg to ioctl is a character
3718 * pointer, which is true on Berkeley systems but not System V. Since
3719 * System V doesn't have job control yet, this isn't a problem now.
3720 *
3721 * Called with interrupts off.
3722 */
3723static void
3724setjobctl(int on)
3725{
3726 int fd;
3727 int pgrp;
3728
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003729 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003730 return;
3731 if (on) {
3732 int ofd;
3733 ofd = fd = open(_PATH_TTY, O_RDWR);
3734 if (fd < 0) {
3735 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3736 * That sometimes helps to acquire controlling tty.
3737 * Obviously, a workaround for bugs when someone
3738 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003739 fd = 2;
3740 while (!isatty(fd))
3741 if (--fd < 0)
3742 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003743 }
3744 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003745 if (ofd >= 0)
3746 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003747 if (fd < 0)
3748 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003749 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003750 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003751 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003752 pgrp = tcgetpgrp(fd);
3753 if (pgrp < 0) {
3754 out:
3755 ash_msg("can't access tty; job control turned off");
3756 mflag = on = 0;
3757 goto close;
3758 }
3759 if (pgrp == getpgrp())
3760 break;
3761 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003762 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003763 initialpgrp = pgrp;
3764
3765 setsignal(SIGTSTP);
3766 setsignal(SIGTTOU);
3767 setsignal(SIGTTIN);
3768 pgrp = rootpid;
3769 setpgid(0, pgrp);
3770 xtcsetpgrp(fd, pgrp);
3771 } else {
3772 /* turning job control off */
3773 fd = ttyfd;
3774 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003775 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003776 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003777 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003778 setpgid(0, pgrp);
3779 setsignal(SIGTSTP);
3780 setsignal(SIGTTOU);
3781 setsignal(SIGTTIN);
3782 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003783 if (fd >= 0)
3784 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003785 fd = -1;
3786 }
3787 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003788 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003789}
3790
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003791static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003792killcmd(int argc, char **argv)
3793{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003794 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003795 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003796 do {
3797 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003798 /*
3799 * "kill %N" - job kill
3800 * Converting to pgrp / pid kill
3801 */
3802 struct job *jp;
3803 char *dst;
3804 int j, n;
3805
3806 jp = getjob(argv[i], 0);
3807 /*
3808 * In jobs started under job control, we signal
3809 * entire process group by kill -PGRP_ID.
3810 * This happens, f.e., in interactive shell.
3811 *
3812 * Otherwise, we signal each child via
3813 * kill PID1 PID2 PID3.
3814 * Testcases:
3815 * sh -c 'sleep 1|sleep 1 & kill %1'
3816 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3817 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3818 */
3819 n = jp->nprocs; /* can't be 0 (I hope) */
3820 if (jp->jobctl)
3821 n = 1;
3822 dst = alloca(n * sizeof(int)*4);
3823 argv[i] = dst;
3824 for (j = 0; j < n; j++) {
3825 struct procstat *ps = &jp->ps[j];
3826 /* Skip non-running and not-stopped members
3827 * (i.e. dead members) of the job
3828 */
3829 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3830 continue;
3831 /*
3832 * kill_main has matching code to expect
3833 * leading space. Needed to not confuse
3834 * negative pids with "kill -SIGNAL_NO" syntax
3835 */
3836 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3837 }
3838 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003839 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003840 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003841 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003842 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003843}
3844
3845static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003846showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003847{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003848 struct procstat *ps;
3849 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003850
Denys Vlasenko285ad152009-12-04 23:02:27 +01003851 psend = jp->ps + jp->nprocs;
3852 for (ps = jp->ps + 1; ps < psend; ps++)
3853 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003854 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003855 flush_stdout_stderr();
3856}
3857
3858
3859static int
3860restartjob(struct job *jp, int mode)
3861{
3862 struct procstat *ps;
3863 int i;
3864 int status;
3865 pid_t pgid;
3866
3867 INT_OFF;
3868 if (jp->state == JOBDONE)
3869 goto out;
3870 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003871 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003872 if (mode == FORK_FG)
3873 xtcsetpgrp(ttyfd, pgid);
3874 killpg(pgid, SIGCONT);
3875 ps = jp->ps;
3876 i = jp->nprocs;
3877 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003878 if (WIFSTOPPED(ps->ps_status)) {
3879 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003880 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003881 ps++;
3882 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883 out:
3884 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3885 INT_ON;
3886 return status;
3887}
3888
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003889static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003890fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003891{
3892 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003893 int mode;
3894 int retval;
3895
3896 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3897 nextopt(nullstr);
3898 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003899 do {
3900 jp = getjob(*argv, 1);
3901 if (mode == FORK_BG) {
3902 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003903 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003904 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003905 out1str(jp->ps[0].ps_cmd);
3906 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003907 retval = restartjob(jp, mode);
3908 } while (*argv && *++argv);
3909 return retval;
3910}
3911#endif
3912
3913static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003914sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003915{
3916 int col;
3917 int st;
3918
3919 col = 0;
3920 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003921 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003922 st = WSTOPSIG(status);
3923 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003924 st = WTERMSIG(status);
3925 if (sigonly) {
3926 if (st == SIGINT || st == SIGPIPE)
3927 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003928 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003929 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003930 }
3931 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003932//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003933 col = fmtstr(s, 32, strsignal(st));
3934 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003935 strcpy(s + col, " (core dumped)");
3936 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003937 }
3938 } else if (!sigonly) {
3939 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003940 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003941 }
3942 out:
3943 return col;
3944}
3945
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003946static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003947dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003948{
3949 int pid;
3950 int status;
3951 struct job *jp;
3952 struct job *thisjob;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003953
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003954 TRACE(("dowait(0x%x) called\n", wait_flags));
3955
3956 /* Do a wait system call. If job control is compiled in, we accept
3957 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3958 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003959 if (doing_jobctl)
3960 wait_flags |= WUNTRACED;
3961 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003962 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3963 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003964 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003965 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003966
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003967 INT_OFF;
3968 thisjob = NULL;
3969 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003970 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003971 struct procstat *ps;
3972 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003973 if (jp->state == JOBDONE)
3974 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003975 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003976 ps = jp->ps;
3977 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003978 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003979 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003980 TRACE(("Job %d: changing status of proc %d "
3981 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003982 jobno(jp), pid, ps->ps_status, status));
3983 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003984 thisjob = jp;
3985 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003986 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003987 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003988#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003989 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003990 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003991 if (WIFSTOPPED(ps->ps_status)) {
3992 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003993 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003994 }
3995#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01003996 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003997 if (!thisjob)
3998 continue;
3999
4000 /* Found the job where one of its processes changed its state.
4001 * Is there at least one live and running process in this job? */
4002 if (jobstate != JOBRUNNING) {
4003 /* No. All live processes in the job are stopped
4004 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4005 */
4006 thisjob->changed = 1;
4007 if (thisjob->state != jobstate) {
4008 TRACE(("Job %d: changing state from %d to %d\n",
4009 jobno(thisjob), thisjob->state, jobstate));
4010 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004011#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004012 if (jobstate == JOBSTOPPED)
4013 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004014#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004015 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004016 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004017 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004018 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004019 /* The process wasn't found in job list */
4020 if (JOBS && !WIFSTOPPED(status))
4021 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004022 out:
4023 INT_ON;
4024
4025 if (thisjob && thisjob == job) {
4026 char s[48 + 1];
4027 int len;
4028
Denys Vlasenko9c541002015-10-07 15:44:36 +02004029 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004030 if (len) {
4031 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004032 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004033 out2str(s);
4034 }
4035 }
4036 return pid;
4037}
4038
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004039static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004040blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004041{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004042 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004043 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004044 raise_exception(EXSIG);
4045 return pid;
4046}
4047
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004048#if JOBS
4049static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004050showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004051{
4052 struct procstat *ps;
4053 struct procstat *psend;
4054 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004055 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004056 char s[16 + 16 + 48];
4057 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004058
4059 ps = jp->ps;
4060
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004061 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004062 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004063 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004064 return;
4065 }
4066
4067 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004068 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004069
4070 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004071 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004073 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004074
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004075 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004076 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077
4078 psend = ps + jp->nprocs;
4079
4080 if (jp->state == JOBRUNNING) {
4081 strcpy(s + col, "Running");
4082 col += sizeof("Running") - 1;
4083 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004084 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004085 if (jp->state == JOBSTOPPED)
4086 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004087 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004088 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004089 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004090
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004091 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4092 * or prints several "PID | <cmdN>" lines,
4093 * depending on SHOW_PIDS bit.
4094 * We do not print status of individual processes
4095 * between PID and <cmdN>. bash does it, but not very well:
4096 * first line shows overall job status, not process status,
4097 * making it impossible to know 1st process status.
4098 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004099 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004100 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004101 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004102 s[0] = '\0';
4103 col = 33;
4104 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004105 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004106 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004107 fprintf(out, "%s%*c%s%s",
4108 s,
4109 33 - col >= 0 ? 33 - col : 0, ' ',
4110 ps == jp->ps ? "" : "| ",
4111 ps->ps_cmd
4112 );
4113 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004114 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004115
4116 jp->changed = 0;
4117
4118 if (jp->state == JOBDONE) {
4119 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4120 freejob(jp);
4121 }
4122}
4123
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004124/*
4125 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4126 * statuses have changed since the last call to showjobs.
4127 */
4128static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004129showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004130{
4131 struct job *jp;
4132
Denys Vlasenko883cea42009-07-11 15:31:59 +02004133 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004134
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004135 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004136 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004137 continue;
4138
4139 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004140 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004141 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004142 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143 }
4144}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004145
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004146static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004147jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004148{
4149 int mode, m;
4150
4151 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004152 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004153 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004154 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004155 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004156 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004157 }
4158
4159 argv = argptr;
4160 if (*argv) {
4161 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004162 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004163 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004164 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004165 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004166 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004167
4168 return 0;
4169}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004170#endif /* JOBS */
4171
Michael Abbott359da5e2009-12-04 23:03:29 +01004172/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004173static int
4174getstatus(struct job *job)
4175{
4176 int status;
4177 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004178 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004179
Michael Abbott359da5e2009-12-04 23:03:29 +01004180 /* Fetch last member's status */
4181 ps = job->ps + job->nprocs - 1;
4182 status = ps->ps_status;
4183 if (pipefail) {
4184 /* "set -o pipefail" mode: use last _nonzero_ status */
4185 while (status == 0 && --ps >= job->ps)
4186 status = ps->ps_status;
4187 }
4188
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189 retval = WEXITSTATUS(status);
4190 if (!WIFEXITED(status)) {
4191#if JOBS
4192 retval = WSTOPSIG(status);
4193 if (!WIFSTOPPED(status))
4194#endif
4195 {
4196 /* XXX: limits number of signals */
4197 retval = WTERMSIG(status);
4198#if JOBS
4199 if (retval == SIGINT)
4200 job->sigint = 1;
4201#endif
4202 }
4203 retval += 128;
4204 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004205 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004206 jobno(job), job->nprocs, status, retval));
4207 return retval;
4208}
4209
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004210static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004211waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004212{
4213 struct job *job;
4214 int retval;
4215 struct job *jp;
4216
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004217 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004218 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004219
4220 nextopt(nullstr);
4221 retval = 0;
4222
4223 argv = argptr;
4224 if (!*argv) {
4225 /* wait for all jobs */
4226 for (;;) {
4227 jp = curjob;
4228 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004229 if (!jp) /* no running procs */
4230 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004231 if (jp->state == JOBRUNNING)
4232 break;
4233 jp->waited = 1;
4234 jp = jp->prev_job;
4235 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004236 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004237 /* man bash:
4238 * "When bash is waiting for an asynchronous command via
4239 * the wait builtin, the reception of a signal for which a trap
4240 * has been set will cause the wait builtin to return immediately
4241 * with an exit status greater than 128, immediately after which
4242 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004243 *
4244 * blocking_wait_with_raise_on_sig raises signal handlers
4245 * if it gets no pid (pid < 0). However,
4246 * if child sends us a signal *and immediately exits*,
4247 * blocking_wait_with_raise_on_sig gets pid > 0
4248 * and does not handle pending_sig. Check this case: */
4249 if (pending_sig)
4250 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004251 }
4252 }
4253
4254 retval = 127;
4255 do {
4256 if (**argv != '%') {
4257 pid_t pid = number(*argv);
4258 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004259 while (1) {
4260 if (!job)
4261 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004262 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004263 break;
4264 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004265 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004266 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004267 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004268 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004269 /* loop until process terminated or stopped */
4270 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004271 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004272 job->waited = 1;
4273 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004274 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004275 } while (*++argv);
4276
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004277 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004278 return retval;
4279}
4280
4281static struct job *
4282growjobtab(void)
4283{
4284 size_t len;
4285 ptrdiff_t offset;
4286 struct job *jp, *jq;
4287
4288 len = njobs * sizeof(*jp);
4289 jq = jobtab;
4290 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4291
4292 offset = (char *)jp - (char *)jq;
4293 if (offset) {
4294 /* Relocate pointers */
4295 size_t l = len;
4296
4297 jq = (struct job *)((char *)jq + l);
4298 while (l) {
4299 l -= sizeof(*jp);
4300 jq--;
4301#define joff(p) ((struct job *)((char *)(p) + l))
4302#define jmove(p) (p) = (void *)((char *)(p) + offset)
4303 if (joff(jp)->ps == &jq->ps0)
4304 jmove(joff(jp)->ps);
4305 if (joff(jp)->prev_job)
4306 jmove(joff(jp)->prev_job);
4307 }
4308 if (curjob)
4309 jmove(curjob);
4310#undef joff
4311#undef jmove
4312 }
4313
4314 njobs += 4;
4315 jobtab = jp;
4316 jp = (struct job *)((char *)jp + len);
4317 jq = jp + 3;
4318 do {
4319 jq->used = 0;
4320 } while (--jq >= jp);
4321 return jp;
4322}
4323
4324/*
4325 * Return a new job structure.
4326 * Called with interrupts off.
4327 */
4328static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004329makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004330{
4331 int i;
4332 struct job *jp;
4333
4334 for (i = njobs, jp = jobtab; ; jp++) {
4335 if (--i < 0) {
4336 jp = growjobtab();
4337 break;
4338 }
4339 if (jp->used == 0)
4340 break;
4341 if (jp->state != JOBDONE || !jp->waited)
4342 continue;
4343#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004344 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004345 continue;
4346#endif
4347 freejob(jp);
4348 break;
4349 }
4350 memset(jp, 0, sizeof(*jp));
4351#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004352 /* jp->jobctl is a bitfield.
4353 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004354 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004355 jp->jobctl = 1;
4356#endif
4357 jp->prev_job = curjob;
4358 curjob = jp;
4359 jp->used = 1;
4360 jp->ps = &jp->ps0;
4361 if (nprocs > 1) {
4362 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4363 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004364 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004365 jobno(jp)));
4366 return jp;
4367}
4368
4369#if JOBS
4370/*
4371 * Return a string identifying a command (to be printed by the
4372 * jobs command).
4373 */
4374static char *cmdnextc;
4375
4376static void
4377cmdputs(const char *s)
4378{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004379 static const char vstype[VSTYPE + 1][3] = {
4380 "", "}", "-", "+", "?", "=",
4381 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004382 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004383 };
4384
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004385 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004386 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004387 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004388 unsigned char c;
4389 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004390 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004391
Denys Vlasenko46a14772009-12-10 21:27:13 +01004392 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004393 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4394 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004395 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004396 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004397 switch (c) {
4398 case CTLESC:
4399 c = *p++;
4400 break;
4401 case CTLVAR:
4402 subtype = *p++;
4403 if ((subtype & VSTYPE) == VSLENGTH)
4404 str = "${#";
4405 else
4406 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004407 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004408 case CTLENDVAR:
4409 str = "\"}" + !(quoted & 1);
4410 quoted >>= 1;
4411 subtype = 0;
4412 goto dostr;
4413 case CTLBACKQ:
4414 str = "$(...)";
4415 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004416#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004417 case CTLARI:
4418 str = "$((";
4419 goto dostr;
4420 case CTLENDARI:
4421 str = "))";
4422 goto dostr;
4423#endif
4424 case CTLQUOTEMARK:
4425 quoted ^= 1;
4426 c = '"';
4427 break;
4428 case '=':
4429 if (subtype == 0)
4430 break;
4431 if ((subtype & VSTYPE) != VSNORMAL)
4432 quoted <<= 1;
4433 str = vstype[subtype & VSTYPE];
4434 if (subtype & VSNUL)
4435 c = ':';
4436 else
4437 goto checkstr;
4438 break;
4439 case '\'':
4440 case '\\':
4441 case '"':
4442 case '$':
4443 /* These can only happen inside quotes */
4444 cc[0] = c;
4445 str = cc;
4446 c = '\\';
4447 break;
4448 default:
4449 break;
4450 }
4451 USTPUTC(c, nextc);
4452 checkstr:
4453 if (!str)
4454 continue;
4455 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004456 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004457 USTPUTC(c, nextc);
4458 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004459 } /* while *p++ not NUL */
4460
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004461 if (quoted & 1) {
4462 USTPUTC('"', nextc);
4463 }
4464 *nextc = 0;
4465 cmdnextc = nextc;
4466}
4467
4468/* cmdtxt() and cmdlist() call each other */
4469static void cmdtxt(union node *n);
4470
4471static void
4472cmdlist(union node *np, int sep)
4473{
4474 for (; np; np = np->narg.next) {
4475 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004476 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004477 cmdtxt(np);
4478 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004479 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004480 }
4481}
4482
4483static void
4484cmdtxt(union node *n)
4485{
4486 union node *np;
4487 struct nodelist *lp;
4488 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004489
4490 if (!n)
4491 return;
4492 switch (n->type) {
4493 default:
4494#if DEBUG
4495 abort();
4496#endif
4497 case NPIPE:
4498 lp = n->npipe.cmdlist;
4499 for (;;) {
4500 cmdtxt(lp->n);
4501 lp = lp->next;
4502 if (!lp)
4503 break;
4504 cmdputs(" | ");
4505 }
4506 break;
4507 case NSEMI:
4508 p = "; ";
4509 goto binop;
4510 case NAND:
4511 p = " && ";
4512 goto binop;
4513 case NOR:
4514 p = " || ";
4515 binop:
4516 cmdtxt(n->nbinary.ch1);
4517 cmdputs(p);
4518 n = n->nbinary.ch2;
4519 goto donode;
4520 case NREDIR:
4521 case NBACKGND:
4522 n = n->nredir.n;
4523 goto donode;
4524 case NNOT:
4525 cmdputs("!");
4526 n = n->nnot.com;
4527 donode:
4528 cmdtxt(n);
4529 break;
4530 case NIF:
4531 cmdputs("if ");
4532 cmdtxt(n->nif.test);
4533 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004534 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004535 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004536 cmdputs("; else ");
4537 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004538 } else {
4539 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004540 }
4541 p = "; fi";
4542 goto dotail;
4543 case NSUBSHELL:
4544 cmdputs("(");
4545 n = n->nredir.n;
4546 p = ")";
4547 goto dotail;
4548 case NWHILE:
4549 p = "while ";
4550 goto until;
4551 case NUNTIL:
4552 p = "until ";
4553 until:
4554 cmdputs(p);
4555 cmdtxt(n->nbinary.ch1);
4556 n = n->nbinary.ch2;
4557 p = "; done";
4558 dodo:
4559 cmdputs("; do ");
4560 dotail:
4561 cmdtxt(n);
4562 goto dotail2;
4563 case NFOR:
4564 cmdputs("for ");
4565 cmdputs(n->nfor.var);
4566 cmdputs(" in ");
4567 cmdlist(n->nfor.args, 1);
4568 n = n->nfor.body;
4569 p = "; done";
4570 goto dodo;
4571 case NDEFUN:
4572 cmdputs(n->narg.text);
4573 p = "() { ... }";
4574 goto dotail2;
4575 case NCMD:
4576 cmdlist(n->ncmd.args, 1);
4577 cmdlist(n->ncmd.redirect, 0);
4578 break;
4579 case NARG:
4580 p = n->narg.text;
4581 dotail2:
4582 cmdputs(p);
4583 break;
4584 case NHERE:
4585 case NXHERE:
4586 p = "<<...";
4587 goto dotail2;
4588 case NCASE:
4589 cmdputs("case ");
4590 cmdputs(n->ncase.expr->narg.text);
4591 cmdputs(" in ");
4592 for (np = n->ncase.cases; np; np = np->nclist.next) {
4593 cmdtxt(np->nclist.pattern);
4594 cmdputs(") ");
4595 cmdtxt(np->nclist.body);
4596 cmdputs(";; ");
4597 }
4598 p = "esac";
4599 goto dotail2;
4600 case NTO:
4601 p = ">";
4602 goto redir;
4603 case NCLOBBER:
4604 p = ">|";
4605 goto redir;
4606 case NAPPEND:
4607 p = ">>";
4608 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004609#if ENABLE_ASH_BASH_COMPAT
4610 case NTO2:
4611#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004612 case NTOFD:
4613 p = ">&";
4614 goto redir;
4615 case NFROM:
4616 p = "<";
4617 goto redir;
4618 case NFROMFD:
4619 p = "<&";
4620 goto redir;
4621 case NFROMTO:
4622 p = "<>";
4623 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004624 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004625 cmdputs(p);
4626 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004627 cmdputs(utoa(n->ndup.dupfd));
4628 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004629 }
4630 n = n->nfile.fname;
4631 goto donode;
4632 }
4633}
4634
4635static char *
4636commandtext(union node *n)
4637{
4638 char *name;
4639
4640 STARTSTACKSTR(cmdnextc);
4641 cmdtxt(n);
4642 name = stackblock();
4643 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4644 name, cmdnextc, cmdnextc));
4645 return ckstrdup(name);
4646}
4647#endif /* JOBS */
4648
4649/*
4650 * Fork off a subshell. If we are doing job control, give the subshell its
4651 * own process group. Jp is a job structure that the job is to be added to.
4652 * N is the command that will be evaluated by the child. Both jp and n may
4653 * be NULL. The mode parameter can be one of the following:
4654 * FORK_FG - Fork off a foreground process.
4655 * FORK_BG - Fork off a background process.
4656 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4657 * process group even if job control is on.
4658 *
4659 * When job control is turned off, background processes have their standard
4660 * input redirected to /dev/null (except for the second and later processes
4661 * in a pipeline).
4662 *
4663 * Called with interrupts off.
4664 */
4665/*
4666 * Clear traps on a fork.
4667 */
4668static void
4669clear_traps(void)
4670{
4671 char **tp;
4672
4673 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004674 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004675 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004676 if (trap_ptr == trap)
4677 free(*tp);
4678 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004679 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004680 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004681 setsignal(tp - trap);
4682 INT_ON;
4683 }
4684 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004685 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004686}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004687
4688/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004689static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004690
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004691/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004692static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004693forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004694{
4695 int oldlvl;
4696
4697 TRACE(("Child shell %d\n", getpid()));
4698 oldlvl = shlvl;
4699 shlvl++;
4700
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004701 /* man bash: "Non-builtin commands run by bash have signal handlers
4702 * set to the values inherited by the shell from its parent".
4703 * Do we do it correctly? */
4704
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004705 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004706
4707 if (mode == FORK_NOJOB /* is it `xxx` ? */
4708 && n && n->type == NCMD /* is it single cmd? */
4709 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004710 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004711 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4712 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4713 ) {
4714 TRACE(("Trap hack\n"));
4715 /* Awful hack for `trap` or $(trap).
4716 *
4717 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4718 * contains an example where "trap" is executed in a subshell:
4719 *
4720 * save_traps=$(trap)
4721 * ...
4722 * eval "$save_traps"
4723 *
4724 * Standard does not say that "trap" in subshell shall print
4725 * parent shell's traps. It only says that its output
4726 * must have suitable form, but then, in the above example
4727 * (which is not supposed to be normative), it implies that.
4728 *
4729 * bash (and probably other shell) does implement it
4730 * (traps are reset to defaults, but "trap" still shows them),
4731 * but as a result, "trap" logic is hopelessly messed up:
4732 *
4733 * # trap
4734 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4735 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4736 * # true | trap <--- trap is in subshell - no output (ditto)
4737 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4738 * trap -- 'echo Ho' SIGWINCH
4739 * # echo `(trap)` <--- in subshell in subshell - output
4740 * trap -- 'echo Ho' SIGWINCH
4741 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4742 * trap -- 'echo Ho' SIGWINCH
4743 *
4744 * The rules when to forget and when to not forget traps
4745 * get really complex and nonsensical.
4746 *
4747 * Our solution: ONLY bare $(trap) or `trap` is special.
4748 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004749 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004750 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004751 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004752 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004753 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004754#if JOBS
4755 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004756 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004757 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004758 pid_t pgrp;
4759
4760 if (jp->nprocs == 0)
4761 pgrp = getpid();
4762 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004763 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004764 /* this can fail because we are doing it in the parent also */
4765 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004766 if (mode == FORK_FG)
4767 xtcsetpgrp(ttyfd, pgrp);
4768 setsignal(SIGTSTP);
4769 setsignal(SIGTTOU);
4770 } else
4771#endif
4772 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004773 /* man bash: "When job control is not in effect,
4774 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004775 ignoresig(SIGINT);
4776 ignoresig(SIGQUIT);
4777 if (jp->nprocs == 0) {
4778 close(0);
4779 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004780 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004781 }
4782 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004783 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004784 if (iflag) { /* why if iflag only? */
4785 setsignal(SIGINT);
4786 setsignal(SIGTERM);
4787 }
4788 /* man bash:
4789 * "In all cases, bash ignores SIGQUIT. Non-builtin
4790 * commands run by bash have signal handlers
4791 * set to the values inherited by the shell
4792 * from its parent".
4793 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004794 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004795 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004796#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004797 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004798 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004799 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004800 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004801 /* "jobs": we do not want to clear job list for it,
4802 * instead we remove only _its_ own_ job from job list.
4803 * This makes "jobs .... | cat" more useful.
4804 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004805 freejob(curjob);
4806 return;
4807 }
4808#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004809 for (jp = curjob; jp; jp = jp->prev_job)
4810 freejob(jp);
4811 jobless = 0;
4812}
4813
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004814/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004815#if !JOBS
4816#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4817#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004818static void
4819forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4820{
4821 TRACE(("In parent shell: child = %d\n", pid));
4822 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004823 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4824 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004825 jobless++;
4826 return;
4827 }
4828#if JOBS
4829 if (mode != FORK_NOJOB && jp->jobctl) {
4830 int pgrp;
4831
4832 if (jp->nprocs == 0)
4833 pgrp = pid;
4834 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004835 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004836 /* This can fail because we are doing it in the child also */
4837 setpgid(pid, pgrp);
4838 }
4839#endif
4840 if (mode == FORK_BG) {
4841 backgndpid = pid; /* set $! */
4842 set_curjob(jp, CUR_RUNNING);
4843 }
4844 if (jp) {
4845 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004846 ps->ps_pid = pid;
4847 ps->ps_status = -1;
4848 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004849#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004850 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004851 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004852#endif
4853 }
4854}
4855
4856static int
4857forkshell(struct job *jp, union node *n, int mode)
4858{
4859 int pid;
4860
4861 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4862 pid = fork();
4863 if (pid < 0) {
4864 TRACE(("Fork failed, errno=%d", errno));
4865 if (jp)
4866 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004867 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004868 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004869 if (pid == 0) {
4870 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004871 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004872 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004873 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004874 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004875 return pid;
4876}
4877
4878/*
4879 * Wait for job to finish.
4880 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004881 * Under job control we have the problem that while a child process
4882 * is running interrupts generated by the user are sent to the child
4883 * but not to the shell. This means that an infinite loop started by
4884 * an interactive user may be hard to kill. With job control turned off,
4885 * an interactive user may place an interactive program inside a loop.
4886 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004887 * these interrupts to also abort the loop. The approach we take here
4888 * is to have the shell ignore interrupt signals while waiting for a
4889 * foreground process to terminate, and then send itself an interrupt
4890 * signal if the child process was terminated by an interrupt signal.
4891 * Unfortunately, some programs want to do a bit of cleanup and then
4892 * exit on interrupt; unless these processes terminate themselves by
4893 * sending a signal to themselves (instead of calling exit) they will
4894 * confuse this approach.
4895 *
4896 * Called with interrupts off.
4897 */
4898static int
4899waitforjob(struct job *jp)
4900{
4901 int st;
4902
4903 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004904
4905 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004906 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004907 /* In non-interactive shells, we _can_ get
4908 * a keyboard signal here and be EINTRed,
4909 * but we just loop back, waiting for command to complete.
4910 *
4911 * man bash:
4912 * "If bash is waiting for a command to complete and receives
4913 * a signal for which a trap has been set, the trap
4914 * will not be executed until the command completes."
4915 *
4916 * Reality is that even if trap is not set, bash
4917 * will not act on the signal until command completes.
4918 * Try this. sleep5intoff.c:
4919 * #include <signal.h>
4920 * #include <unistd.h>
4921 * int main() {
4922 * sigset_t set;
4923 * sigemptyset(&set);
4924 * sigaddset(&set, SIGINT);
4925 * sigaddset(&set, SIGQUIT);
4926 * sigprocmask(SIG_BLOCK, &set, NULL);
4927 * sleep(5);
4928 * return 0;
4929 * }
4930 * $ bash -c './sleep5intoff; echo hi'
4931 * ^C^C^C^C <--- pressing ^C once a second
4932 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004933 * $ bash -c './sleep5intoff; echo hi'
4934 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4935 * $ _
4936 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004937 dowait(DOWAIT_BLOCK, jp);
4938 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004939 INT_ON;
4940
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004941 st = getstatus(jp);
4942#if JOBS
4943 if (jp->jobctl) {
4944 xtcsetpgrp(ttyfd, rootpid);
4945 /*
4946 * This is truly gross.
4947 * If we're doing job control, then we did a TIOCSPGRP which
4948 * caused us (the shell) to no longer be in the controlling
4949 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4950 * intuit from the subprocess exit status whether a SIGINT
4951 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4952 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004953 if (jp->sigint) /* TODO: do the same with all signals */
4954 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004955 }
4956 if (jp->state == JOBDONE)
4957#endif
4958 freejob(jp);
4959 return st;
4960}
4961
4962/*
4963 * return 1 if there are stopped jobs, otherwise 0
4964 */
4965static int
4966stoppedjobs(void)
4967{
4968 struct job *jp;
4969 int retval;
4970
4971 retval = 0;
4972 if (job_warning)
4973 goto out;
4974 jp = curjob;
4975 if (jp && jp->state == JOBSTOPPED) {
4976 out2str("You have stopped jobs.\n");
4977 job_warning = 2;
4978 retval++;
4979 }
4980 out:
4981 return retval;
4982}
4983
4984
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004985/* ============ redir.c
4986 *
4987 * Code for dealing with input/output redirection.
4988 */
4989
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01004990#undef EMPTY
4991#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004992#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00004993#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004994
4995/*
4996 * Open a file in noclobber mode.
4997 * The code was copied from bash.
4998 */
4999static int
5000noclobberopen(const char *fname)
5001{
5002 int r, fd;
5003 struct stat finfo, finfo2;
5004
5005 /*
5006 * If the file exists and is a regular file, return an error
5007 * immediately.
5008 */
5009 r = stat(fname, &finfo);
5010 if (r == 0 && S_ISREG(finfo.st_mode)) {
5011 errno = EEXIST;
5012 return -1;
5013 }
5014
5015 /*
5016 * If the file was not present (r != 0), make sure we open it
5017 * exclusively so that if it is created before we open it, our open
5018 * will fail. Make sure that we do not truncate an existing file.
5019 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5020 * file was not a regular file, we leave O_EXCL off.
5021 */
5022 if (r != 0)
5023 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5024 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5025
5026 /* If the open failed, return the file descriptor right away. */
5027 if (fd < 0)
5028 return fd;
5029
5030 /*
5031 * OK, the open succeeded, but the file may have been changed from a
5032 * non-regular file to a regular file between the stat and the open.
5033 * We are assuming that the O_EXCL open handles the case where FILENAME
5034 * did not exist and is symlinked to an existing file between the stat
5035 * and open.
5036 */
5037
5038 /*
5039 * If we can open it and fstat the file descriptor, and neither check
5040 * revealed that it was a regular file, and the file has not been
5041 * replaced, return the file descriptor.
5042 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005043 if (fstat(fd, &finfo2) == 0
5044 && !S_ISREG(finfo2.st_mode)
5045 && finfo.st_dev == finfo2.st_dev
5046 && finfo.st_ino == finfo2.st_ino
5047 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005048 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005049 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005050
5051 /* The file has been replaced. badness. */
5052 close(fd);
5053 errno = EEXIST;
5054 return -1;
5055}
5056
5057/*
5058 * Handle here documents. Normally we fork off a process to write the
5059 * data to a pipe. If the document is short, we can stuff the data in
5060 * the pipe without forking.
5061 */
5062/* openhere needs this forward reference */
5063static void expandhere(union node *arg, int fd);
5064static int
5065openhere(union node *redir)
5066{
5067 int pip[2];
5068 size_t len = 0;
5069
5070 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005071 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005072 if (redir->type == NHERE) {
5073 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005074 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005075 full_write(pip[1], redir->nhere.doc->narg.text, len);
5076 goto out;
5077 }
5078 }
5079 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005080 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005081 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005082 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5083 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5084 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5085 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005086 signal(SIGPIPE, SIG_DFL);
5087 if (redir->type == NHERE)
5088 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005089 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005090 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005091 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005092 }
5093 out:
5094 close(pip[1]);
5095 return pip[0];
5096}
5097
5098static int
5099openredirect(union node *redir)
5100{
5101 char *fname;
5102 int f;
5103
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02005104 fname = redir->nfile.expfname;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005105 switch (redir->nfile.type) {
5106 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005107 f = open(fname, O_RDONLY);
5108 if (f < 0)
5109 goto eopen;
5110 break;
5111 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005112 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005113 if (f < 0)
5114 goto ecreate;
5115 break;
5116 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005117#if ENABLE_ASH_BASH_COMPAT
5118 case NTO2:
5119#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005120 /* Take care of noclobber mode. */
5121 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005122 f = noclobberopen(fname);
5123 if (f < 0)
5124 goto ecreate;
5125 break;
5126 }
5127 /* FALLTHROUGH */
5128 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005129 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5130 if (f < 0)
5131 goto ecreate;
5132 break;
5133 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005134 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5135 if (f < 0)
5136 goto ecreate;
5137 break;
5138 default:
5139#if DEBUG
5140 abort();
5141#endif
5142 /* Fall through to eliminate warning. */
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005143/* Our single caller does this itself */
Denis Vlasenko0b769642008-07-24 07:54:57 +00005144// case NTOFD:
5145// case NFROMFD:
5146// f = -1;
5147// break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005148 case NHERE:
5149 case NXHERE:
5150 f = openhere(redir);
5151 break;
5152 }
5153
5154 return f;
5155 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005156 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005157 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005158 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005159}
5160
5161/*
5162 * Copy a file descriptor to be >= to. Returns -1
5163 * if the source file descriptor is closed, EMPTY if there are no unused
5164 * file descriptors left.
5165 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005166/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5167 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005168enum {
5169 COPYFD_EXACT = (int)~(INT_MAX),
5170 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5171};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005172static int
5173copyfd(int from, int to)
5174{
5175 int newfd;
5176
Denis Vlasenko5a867312008-07-24 19:46:38 +00005177 if (to & COPYFD_EXACT) {
5178 to &= ~COPYFD_EXACT;
5179 /*if (from != to)*/
5180 newfd = dup2(from, to);
5181 } else {
5182 newfd = fcntl(from, F_DUPFD, to);
5183 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005184 if (newfd < 0) {
5185 if (errno == EMFILE)
5186 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005187 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005188 ash_msg_and_raise_error("%d: %m", from);
5189 }
5190 return newfd;
5191}
5192
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005193/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005194struct two_fd_t {
5195 int orig, copy;
5196};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005197struct redirtab {
5198 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005199 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005200 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005201 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005202};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005203#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005204
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005205static int need_to_remember(struct redirtab *rp, int fd)
5206{
5207 int i;
5208
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005209 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005210 return 0;
5211
5212 for (i = 0; i < rp->pair_count; i++) {
5213 if (rp->two_fd[i].orig == fd) {
5214 /* already remembered */
5215 return 0;
5216 }
5217 }
5218 return 1;
5219}
5220
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005221/* "hidden" fd is a fd used to read scripts, or a copy of such */
5222static int is_hidden_fd(struct redirtab *rp, int fd)
5223{
5224 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005225 struct parsefile *pf;
5226
5227 if (fd == -1)
5228 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005229 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005230 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005231 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005232 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005233 * $ ash # running ash interactively
5234 * $ . ./script.sh
5235 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005236 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005237 * it's still ok to use it: "read" builtin uses it,
5238 * why should we cripple "exec" builtin?
5239 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005240 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005241 return 1;
5242 }
5243 pf = pf->prev;
5244 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005245
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005246 if (!rp)
5247 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005248 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005249 fd |= COPYFD_RESTORE;
5250 for (i = 0; i < rp->pair_count; i++) {
5251 if (rp->two_fd[i].copy == fd) {
5252 return 1;
5253 }
5254 }
5255 return 0;
5256}
5257
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005258/*
5259 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5260 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005261 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005262 */
5263/* flags passed to redirect */
5264#define REDIR_PUSH 01 /* save previous values of file descriptors */
5265#define REDIR_SAVEFD2 03 /* set preverrout */
5266static void
5267redirect(union node *redir, int flags)
5268{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005269 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005270 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005271 int i;
5272 int fd;
5273 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005274 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005275
Denis Vlasenko01631112007-12-16 17:20:38 +00005276 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005277 if (!redir) {
5278 return;
5279 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005280
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005281 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005282 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005283 INT_OFF;
5284 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005285 union node *tmp = redir;
5286 do {
5287 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005288#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005289 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005290 sv_pos++;
5291#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005292 tmp = tmp->nfile.next;
5293 } while (tmp);
5294 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005295 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005296 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005297 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005298 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005299 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005300 while (sv_pos > 0) {
5301 sv_pos--;
5302 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5303 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005304 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005305
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005306 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005307 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005308 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005309 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005310 right_fd = redir->ndup.dupfd;
5311 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005312 /* redirect from/to same file descriptor? */
5313 if (right_fd == fd)
5314 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005315 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005316 if (is_hidden_fd(sv, right_fd)) {
5317 errno = EBADF; /* as if it is closed */
5318 ash_msg_and_raise_error("%d: %m", right_fd);
5319 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005320 newfd = -1;
5321 } else {
5322 newfd = openredirect(redir); /* always >= 0 */
5323 if (fd == newfd) {
5324 /* Descriptor wasn't open before redirect.
5325 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005326 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005327 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005328 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005329 continue;
5330 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005331 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005332#if ENABLE_ASH_BASH_COMPAT
5333 redirect_more:
5334#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005335 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005336 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005337 /* Careful to not accidentally "save"
5338 * to the same fd as right side fd in N>&M */
5339 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5340 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005341/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5342 * are closed in popredir() in the child, preventing them from leaking
5343 * into child. (popredir() also cleans up the mess in case of failures)
5344 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005345 if (i == -1) {
5346 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005347 if (i != EBADF) {
5348 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005349 if (newfd >= 0)
5350 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005351 errno = i;
5352 ash_msg_and_raise_error("%d: %m", fd);
5353 /* NOTREACHED */
5354 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005355 /* EBADF: it is not open - good, remember to close it */
5356 remember_to_close:
5357 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005358 } else { /* fd is open, save its copy */
5359 /* "exec fd>&-" should not close fds
5360 * which point to script file(s).
5361 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005362 if (is_hidden_fd(sv, fd))
5363 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005364 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005365 if (fd == 2)
5366 copied_fd2 = i;
5367 sv->two_fd[sv_pos].orig = fd;
5368 sv->two_fd[sv_pos].copy = i;
5369 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005370 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005371 if (newfd < 0) {
5372 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005373 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005374 /* Don't want to trigger debugging */
5375 if (fd != -1)
5376 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005377 } else {
5378 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005379 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005380 } else if (fd != newfd) { /* move newfd to fd */
5381 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005382#if ENABLE_ASH_BASH_COMPAT
5383 if (!(redir->nfile.type == NTO2 && fd == 2))
5384#endif
5385 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005386 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005387#if ENABLE_ASH_BASH_COMPAT
5388 if (redir->nfile.type == NTO2 && fd == 1) {
5389 /* We already redirected it to fd 1, now copy it to 2 */
5390 newfd = 1;
5391 fd = 2;
5392 goto redirect_more;
5393 }
5394#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005395 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005396
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005397 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005398 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5399 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005400}
5401
5402/*
5403 * Undo the effects of the last redirection.
5404 */
5405static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005406popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005407{
5408 struct redirtab *rp;
5409 int i;
5410
Ron Yorston95650a82015-10-30 19:07:37 +00005411 if (--g_nullredirs >= 0 || redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005412 return;
5413 INT_OFF;
5414 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005415 for (i = 0; i < rp->pair_count; i++) {
5416 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005417 int copy = rp->two_fd[i].copy;
5418 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005419 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005420 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005421 continue;
5422 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005423 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005424 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005425 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005426 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005427 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005428 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005429 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005430 }
5431 }
5432 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005433 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005434 free(rp);
5435 INT_ON;
5436}
5437
5438/*
5439 * Undo all redirections. Called on error or interrupt.
5440 */
5441
5442/*
5443 * Discard all saved file descriptors.
5444 */
5445static void
5446clearredir(int drop)
5447{
5448 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005449 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005450 if (!redirlist)
5451 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005452 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005453 }
5454}
5455
5456static int
5457redirectsafe(union node *redir, int flags)
5458{
5459 int err;
5460 volatile int saveint;
5461 struct jmploc *volatile savehandler = exception_handler;
5462 struct jmploc jmploc;
5463
5464 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005465 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5466 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005467 if (!err) {
5468 exception_handler = &jmploc;
5469 redirect(redir, flags);
5470 }
5471 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005472 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005473 longjmp(exception_handler->loc, 1);
5474 RESTORE_INT(saveint);
5475 return err;
5476}
5477
5478
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005479/* ============ Routines to expand arguments to commands
5480 *
5481 * We have to deal with backquotes, shell variables, and file metacharacters.
5482 */
5483
Mike Frysinger98c52642009-04-02 10:02:37 +00005484#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005485static arith_t
5486ash_arith(const char *s)
5487{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005488 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005489 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005490
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005491 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005492 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005493 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005494
5495 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005496 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005497 if (math_state.errmsg)
5498 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005499 INT_ON;
5500
5501 return result;
5502}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005503#endif
5504
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005505/*
5506 * expandarg flags
5507 */
5508#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5509#define EXP_TILDE 0x2 /* do normal tilde expansion */
5510#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5511#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5512#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005513#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005514#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5515#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005516#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005517/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005518 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005519 */
5520#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5521#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005522#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5523#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005524#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005525
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005526/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005527#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005528/* Do not skip NUL characters. */
5529#define QUOTES_KEEPNUL EXP_TILDE
5530
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005531/*
5532 * Structure specifying which parts of the string should be searched
5533 * for IFS characters.
5534 */
5535struct ifsregion {
5536 struct ifsregion *next; /* next region in list */
5537 int begoff; /* offset of start of region */
5538 int endoff; /* offset of end of region */
5539 int nulonly; /* search for nul bytes only */
5540};
5541
5542struct arglist {
5543 struct strlist *list;
5544 struct strlist **lastp;
5545};
5546
5547/* output of current string */
5548static char *expdest;
5549/* list of back quote expressions */
5550static struct nodelist *argbackq;
5551/* first struct in list of ifs regions */
5552static struct ifsregion ifsfirst;
5553/* last struct in list */
5554static struct ifsregion *ifslastp;
5555/* holds expanded arg list */
5556static struct arglist exparg;
5557
5558/*
5559 * Our own itoa().
5560 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005561#if !ENABLE_SH_MATH_SUPPORT
5562/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5563typedef long arith_t;
5564# define ARITH_FMT "%ld"
5565#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005566static int
5567cvtnum(arith_t num)
5568{
5569 int len;
5570
Denys Vlasenko9c541002015-10-07 15:44:36 +02005571 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5572 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005573 STADJUST(len, expdest);
5574 return len;
5575}
5576
5577static size_t
5578esclen(const char *start, const char *p)
5579{
5580 size_t esc = 0;
5581
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005582 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005583 esc++;
5584 }
5585 return esc;
5586}
5587
5588/*
5589 * Remove any CTLESC characters from a string.
5590 */
5591static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005592rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005593{
Ron Yorston417622c2015-05-18 09:59:14 +02005594 static const char qchars[] ALIGN1 = {
5595 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005596
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005597 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005598 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005599 unsigned protect_against_glob;
5600 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005601 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005602
Ron Yorston417622c2015-05-18 09:59:14 +02005603 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005604 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005605 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005606
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005607 q = p;
5608 r = str;
5609 if (flag & RMESCAPE_ALLOC) {
5610 size_t len = p - str;
5611 size_t fulllen = len + strlen(p) + 1;
5612
5613 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005614 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005615 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005616 /* p and str may be invalidated by makestrspace */
5617 str = (char *)stackblock() + strloc;
5618 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005619 } else if (flag & RMESCAPE_HEAP) {
5620 r = ckmalloc(fulllen);
5621 } else {
5622 r = stalloc(fulllen);
5623 }
5624 q = r;
5625 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005626 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005627 }
5628 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005629
Ron Yorston549deab2015-05-18 09:57:51 +02005630 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005631 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005632 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005633 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005634 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005635// Note: both inquotes and protect_against_glob only affect whether
5636// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005637 inquotes = ~inquotes;
5638 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005639 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005640 continue;
5641 }
Ron Yorston549deab2015-05-18 09:57:51 +02005642 if ((unsigned char)*p == CTLESC) {
5643 p++;
5644 if (protect_against_glob) {
5645 *q++ = '\\';
5646 }
5647 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005648 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005649 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005650 goto copy;
5651 }
Ron Yorston417622c2015-05-18 09:59:14 +02005652#if ENABLE_ASH_BASH_COMPAT
5653 else if (*p == '/' && slash) {
5654 /* stop handling globbing and mark location of slash */
5655 globbing = slash = 0;
5656 *p = CTLESC;
5657 }
5658#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005659 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005660 copy:
5661 *q++ = *p++;
5662 }
5663 *q = '\0';
5664 if (flag & RMESCAPE_GROW) {
5665 expdest = r;
5666 STADJUST(q - r + 1, expdest);
5667 }
5668 return r;
5669}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005670#define pmatch(a, b) !fnmatch((a), (b), 0)
5671
5672/*
5673 * Prepare a pattern for a expmeta (internal glob(3)) call.
5674 *
5675 * Returns an stalloced string.
5676 */
5677static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005678preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005679{
Ron Yorston549deab2015-05-18 09:57:51 +02005680 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005681}
5682
5683/*
5684 * Put a string on the stack.
5685 */
5686static void
5687memtodest(const char *p, size_t len, int syntax, int quotes)
5688{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005689 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005690
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005691 if (!len)
5692 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005693
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005694 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5695
5696 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005697 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005698 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005699 int n = SIT(c, syntax);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005700 if ((quotes & QUOTES_ESC) &&
Ron Yorston549deab2015-05-18 09:57:51 +02005701 ((n == CCTL) ||
5702 (((quotes & EXP_FULL) || syntax != BASESYNTAX) &&
5703 n == CBACK)))
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005704 USTPUTC(CTLESC, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005705 } else if (!(quotes & QUOTES_KEEPNUL))
5706 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005707 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005708 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005709
5710 expdest = q;
5711}
5712
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005713static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005714strtodest(const char *p, int syntax, int quotes)
5715{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005716 size_t len = strlen(p);
5717 memtodest(p, len, syntax, quotes);
5718 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005719}
5720
5721/*
5722 * Record the fact that we have to scan this region of the
5723 * string for IFS characters.
5724 */
5725static void
5726recordregion(int start, int end, int nulonly)
5727{
5728 struct ifsregion *ifsp;
5729
5730 if (ifslastp == NULL) {
5731 ifsp = &ifsfirst;
5732 } else {
5733 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005734 ifsp = ckzalloc(sizeof(*ifsp));
5735 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005736 ifslastp->next = ifsp;
5737 INT_ON;
5738 }
5739 ifslastp = ifsp;
5740 ifslastp->begoff = start;
5741 ifslastp->endoff = end;
5742 ifslastp->nulonly = nulonly;
5743}
5744
5745static void
5746removerecordregions(int endoff)
5747{
5748 if (ifslastp == NULL)
5749 return;
5750
5751 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005752 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005753 struct ifsregion *ifsp;
5754 INT_OFF;
5755 ifsp = ifsfirst.next->next;
5756 free(ifsfirst.next);
5757 ifsfirst.next = ifsp;
5758 INT_ON;
5759 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005760 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005761 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005762 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005763 ifslastp = &ifsfirst;
5764 ifsfirst.endoff = endoff;
5765 }
5766 return;
5767 }
5768
5769 ifslastp = &ifsfirst;
5770 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005771 ifslastp = ifslastp->next;
5772 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005773 struct ifsregion *ifsp;
5774 INT_OFF;
5775 ifsp = ifslastp->next->next;
5776 free(ifslastp->next);
5777 ifslastp->next = ifsp;
5778 INT_ON;
5779 }
5780 if (ifslastp->endoff > endoff)
5781 ifslastp->endoff = endoff;
5782}
5783
5784static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005785exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005786{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005787 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005788 char *name;
5789 struct passwd *pw;
5790 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005791 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005792
5793 name = p + 1;
5794
5795 while ((c = *++p) != '\0') {
5796 switch (c) {
5797 case CTLESC:
5798 return startp;
5799 case CTLQUOTEMARK:
5800 return startp;
5801 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005802 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005803 goto done;
5804 break;
5805 case '/':
5806 case CTLENDVAR:
5807 goto done;
5808 }
5809 }
5810 done:
5811 *p = '\0';
5812 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005813 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005814 } else {
5815 pw = getpwnam(name);
5816 if (pw == NULL)
5817 goto lose;
5818 home = pw->pw_dir;
5819 }
5820 if (!home || !*home)
5821 goto lose;
5822 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005823 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005824 return p;
5825 lose:
5826 *p = c;
5827 return startp;
5828}
5829
5830/*
5831 * Execute a command inside back quotes. If it's a builtin command, we
5832 * want to save its output in a block obtained from malloc. Otherwise
5833 * we fork off a subprocess and get the output of the command via a pipe.
5834 * Should be called with interrupts off.
5835 */
5836struct backcmd { /* result of evalbackcmd */
5837 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005838 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005839 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005840 struct job *jp; /* job structure for command */
5841};
5842
5843/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005844static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005845#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02005846static void evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005847
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005848static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005849evalbackcmd(union node *n, struct backcmd *result)
5850{
5851 int saveherefd;
5852
5853 result->fd = -1;
5854 result->buf = NULL;
5855 result->nleft = 0;
5856 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005857 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005858 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005859
5860 saveherefd = herefd;
5861 herefd = -1;
5862
5863 {
5864 int pip[2];
5865 struct job *jp;
5866
5867 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005868 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005869 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005870 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5871 FORCE_INT_ON;
5872 close(pip[0]);
5873 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005874 /*close(1);*/
5875 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005876 close(pip[1]);
5877 }
5878 eflag = 0;
5879 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5880 /* NOTREACHED */
5881 }
5882 close(pip[1]);
5883 result->fd = pip[0];
5884 result->jp = jp;
5885 }
5886 herefd = saveherefd;
5887 out:
5888 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5889 result->fd, result->buf, result->nleft, result->jp));
5890}
5891
5892/*
5893 * Expand stuff in backwards quotes.
5894 */
5895static void
Ron Yorston549deab2015-05-18 09:57:51 +02005896expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005897{
5898 struct backcmd in;
5899 int i;
5900 char buf[128];
5901 char *p;
5902 char *dest;
5903 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02005904 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005905 struct stackmark smark;
5906
5907 INT_OFF;
5908 setstackmark(&smark);
5909 dest = expdest;
5910 startloc = dest - (char *)stackblock();
5911 grabstackstr(dest);
5912 evalbackcmd(cmd, &in);
5913 popstackmark(&smark);
5914
5915 p = in.buf;
5916 i = in.nleft;
5917 if (i == 0)
5918 goto read;
5919 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02005920 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005921 read:
5922 if (in.fd < 0)
5923 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01005924 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005925 TRACE(("expbackq: read returns %d\n", i));
5926 if (i <= 0)
5927 break;
5928 p = buf;
5929 }
5930
Denis Vlasenko60818682007-09-28 22:07:23 +00005931 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005932 if (in.fd >= 0) {
5933 close(in.fd);
5934 back_exitstatus = waitforjob(in.jp);
5935 }
5936 INT_ON;
5937
5938 /* Eat all trailing newlines */
5939 dest = expdest;
5940 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5941 STUNPUTC(dest);
5942 expdest = dest;
5943
Ron Yorston549deab2015-05-18 09:57:51 +02005944 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005945 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005946 TRACE(("evalbackq: size:%d:'%.*s'\n",
5947 (int)((dest - (char *)stackblock()) - startloc),
5948 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005949 stackblock() + startloc));
5950}
5951
Mike Frysinger98c52642009-04-02 10:02:37 +00005952#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005953/*
5954 * Expand arithmetic expression. Backup to start of expression,
5955 * evaluate, place result in (backed up) result, adjust string position.
5956 */
5957static void
Ron Yorston549deab2015-05-18 09:57:51 +02005958expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005959{
5960 char *p, *start;
5961 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005962 int len;
5963
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005964 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005965
5966 /*
5967 * This routine is slightly over-complicated for
5968 * efficiency. Next we scan backwards looking for the
5969 * start of arithmetic.
5970 */
5971 start = stackblock();
5972 p = expdest - 1;
5973 *p = '\0';
5974 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005975 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005976 int esc;
5977
Denys Vlasenkocd716832009-11-28 22:14:02 +01005978 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005979 p--;
5980#if DEBUG
5981 if (p < start) {
5982 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5983 }
5984#endif
5985 }
5986
5987 esc = esclen(start, p);
5988 if (!(esc % 2)) {
5989 break;
5990 }
5991
5992 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005993 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005994
5995 begoff = p - start;
5996
5997 removerecordregions(begoff);
5998
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005999 expdest = p;
6000
Ron Yorston549deab2015-05-18 09:57:51 +02006001 if (flag & QUOTES_ESC)
6002 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006003
Ron Yorston549deab2015-05-18 09:57:51 +02006004 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006005
Ron Yorston549deab2015-05-18 09:57:51 +02006006 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006007 recordregion(begoff, begoff + len, 0);
6008}
6009#endif
6010
6011/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006012static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006013
6014/*
6015 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6016 * characters to allow for further processing. Otherwise treat
6017 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006018 *
6019 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6020 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6021 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006022 */
6023static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006024argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006025{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006026 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006027 '=',
6028 ':',
6029 CTLQUOTEMARK,
6030 CTLENDVAR,
6031 CTLESC,
6032 CTLVAR,
6033 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006034#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006035 CTLENDARI,
6036#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006037 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006038 };
6039 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006040 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006041 int inquotes;
6042 size_t length;
6043 int startloc;
6044
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006045 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006046 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006047 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006048 reject++;
6049 }
6050 inquotes = 0;
6051 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006052 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006053 char *q;
6054
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006055 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006056 tilde:
6057 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006058 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006059 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006060 }
6061 start:
6062 startloc = expdest - (char *)stackblock();
6063 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006064 unsigned char c;
6065
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006066 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006067 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006068 if (c) {
6069 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006070 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006071 ) {
6072 /* c == '=' || c == ':' || c == CTLENDARI */
6073 length++;
6074 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006075 }
6076 if (length > 0) {
6077 int newloc;
6078 expdest = stack_nputstr(p, length, expdest);
6079 newloc = expdest - (char *)stackblock();
6080 if (breakall && !inquotes && newloc > startloc) {
6081 recordregion(startloc, newloc, 0);
6082 }
6083 startloc = newloc;
6084 }
6085 p += length + 1;
6086 length = 0;
6087
6088 switch (c) {
6089 case '\0':
6090 goto breakloop;
6091 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006092 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006093 p--;
6094 continue;
6095 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006096 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006097 reject++;
6098 /* fall through */
6099 case ':':
6100 /*
6101 * sort of a hack - expand tildes in variable
6102 * assignments (after the first '=' and after ':'s).
6103 */
6104 if (*--p == '~') {
6105 goto tilde;
6106 }
6107 continue;
6108 }
6109
6110 switch (c) {
6111 case CTLENDVAR: /* ??? */
6112 goto breakloop;
6113 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006114 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006115 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006116 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6117 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006118 goto start;
6119 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006120 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006121 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006122 p--;
6123 length++;
6124 startloc++;
6125 }
6126 break;
6127 case CTLESC:
6128 startloc++;
6129 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006130
6131 /*
6132 * Quoted parameter expansion pattern: remove quote
6133 * unless inside inner quotes or we have a literal
6134 * backslash.
6135 */
6136 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6137 EXP_QPAT && *p != '\\')
6138 break;
6139
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006140 goto addquote;
6141 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006142 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006143 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006144 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006145 goto start;
6146 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006147 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006148 argbackq = argbackq->next;
6149 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006150#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006151 case CTLENDARI:
6152 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006153 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006154 goto start;
6155#endif
6156 }
6157 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006158 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006159}
6160
6161static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006162scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6163 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006164{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006165 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006166 char c;
6167
6168 loc = startp;
6169 loc2 = rmesc;
6170 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006171 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006173
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006174 c = *loc2;
6175 if (zero) {
6176 *loc2 = '\0';
6177 s = rmesc;
6178 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006179 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006180
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006181 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006182 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006183 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006184 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006185 loc++;
6186 loc++;
6187 loc2++;
6188 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006189 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006190}
6191
6192static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006193scanright(char *startp, char *rmesc, char *rmescend,
6194 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006195{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006196#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6197 int try2optimize = match_at_start;
6198#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006199 int esc = 0;
6200 char *loc;
6201 char *loc2;
6202
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006203 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6204 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6205 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6206 * Logic:
6207 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6208 * and on each iteration they go back two/one char until they reach the beginning.
6209 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6210 */
6211 /* TODO: document in what other circumstances we are called. */
6212
6213 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006214 int match;
6215 char c = *loc2;
6216 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006217 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006218 *loc2 = '\0';
6219 s = rmesc;
6220 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006221 match = pmatch(pattern, s);
6222 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006223 *loc2 = c;
6224 if (match)
6225 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006226#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6227 if (try2optimize) {
6228 /* Maybe we can optimize this:
6229 * if pattern ends with unescaped *, we can avoid checking
6230 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6231 * it wont match truncated "raw_value_of_" strings too.
6232 */
6233 unsigned plen = strlen(pattern);
6234 /* Does it end with "*"? */
6235 if (plen != 0 && pattern[--plen] == '*') {
6236 /* "xxxx*" is not escaped */
6237 /* "xxx\*" is escaped */
6238 /* "xx\\*" is not escaped */
6239 /* "x\\\*" is escaped */
6240 int slashes = 0;
6241 while (plen != 0 && pattern[--plen] == '\\')
6242 slashes++;
6243 if (!(slashes & 1))
6244 break; /* ends with unescaped "*" */
6245 }
6246 try2optimize = 0;
6247 }
6248#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006249 loc--;
6250 if (quotes) {
6251 if (--esc < 0) {
6252 esc = esclen(startp, loc);
6253 }
6254 if (esc % 2) {
6255 esc--;
6256 loc--;
6257 }
6258 }
6259 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006260 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006261}
6262
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006263static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006264static void
6265varunset(const char *end, const char *var, const char *umsg, int varflags)
6266{
6267 const char *msg;
6268 const char *tail;
6269
6270 tail = nullstr;
6271 msg = "parameter not set";
6272 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006273 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006274 if (varflags & VSNUL)
6275 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006276 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006277 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006278 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006279 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006280 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006281}
6282
6283static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006284subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006285 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006286{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006287 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006288 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006289 char *startp;
6290 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006291 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006292 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006293 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006294 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006295 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006296 int amount, resetloc;
6297 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006298 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006299 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006300
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006301 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6302 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006303
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006304 herefd = -1;
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006305 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006306 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6307 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006308 STPUTC('\0', expdest);
6309 herefd = saveherefd;
6310 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006311 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006312
6313 switch (subtype) {
6314 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006315 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006316 amount = startp - expdest;
6317 STADJUST(amount, expdest);
6318 return startp;
6319
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006320 case VSQUESTION:
6321 varunset(p, varname, startp, varflags);
6322 /* NOTREACHED */
6323
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006324#if ENABLE_ASH_BASH_COMPAT
6325 case VSSUBSTR:
6326 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006327 /* Read POS in ${var:POS:LEN} */
6328 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006329 len = str - startp - 1;
6330
6331 /* *loc != '\0', guaranteed by parser */
6332 if (quotes) {
6333 char *ptr;
6334
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006335 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006336 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006337 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006338 len--;
6339 ptr++;
6340 }
6341 }
6342 }
6343 orig_len = len;
6344
6345 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006346 /* ${var::LEN} */
6347 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006348 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006349 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006350 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006351 while (*loc && *loc != ':') {
6352 /* TODO?
6353 * bash complains on: var=qwe; echo ${var:1a:123}
6354 if (!isdigit(*loc))
6355 ash_msg_and_raise_error(msg_illnum, str);
6356 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006357 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006358 }
6359 if (*loc++ == ':') {
6360 len = number(loc);
6361 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006362 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006363 if (pos < 0) {
6364 /* ${VAR:$((-n)):l} starts n chars from the end */
6365 pos = orig_len + pos;
6366 }
6367 if ((unsigned)pos >= orig_len) {
6368 /* apart from obvious ${VAR:999999:l},
6369 * covers ${VAR:$((-9999999)):l} - result is ""
6370 * (bash-compat)
6371 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006372 pos = 0;
6373 len = 0;
6374 }
6375 if (len > (orig_len - pos))
6376 len = orig_len - pos;
6377
6378 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006379 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006380 str++;
6381 }
6382 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006383 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006384 *loc++ = *str++;
6385 *loc++ = *str++;
6386 }
6387 *loc = '\0';
6388 amount = loc - expdest;
6389 STADJUST(amount, expdest);
6390 return loc;
6391#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006392 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006393
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006394 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006395
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006396 /* We'll comeback here if we grow the stack while handling
6397 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6398 * stack will need rebasing, and we'll need to remove our work
6399 * areas each time
6400 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006401 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006402
6403 amount = expdest - ((char *)stackblock() + resetloc);
6404 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006405 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006406
6407 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006408 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006409 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006410 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006411 if (rmesc != startp) {
6412 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006413 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006414 }
6415 }
6416 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006417 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006418 /*
6419 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6420 * The result is a_\_z_c (not a\_\_z_c)!
6421 *
6422 * The search pattern and replace string treat backslashes differently!
6423 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6424 * and string. It's only used on the first call.
6425 */
6426 preglob(str, IF_ASH_BASH_COMPAT(
6427 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6428 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006430#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006431 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006432 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006433 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006434
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006435 if (!repl) {
Ron Yorston417622c2015-05-18 09:59:14 +02006436 if ((repl=strchr(str, CTLESC)))
6437 *repl++ = '\0';
6438 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006439 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006440 }
Ron Yorston417622c2015-05-18 09:59:14 +02006441 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006442
6443 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006444 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006445 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006446
6447 len = 0;
6448 idx = startp;
6449 end = str - 1;
6450 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006451 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006452 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006453 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006454 if (!loc) {
6455 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006456 char *restart_detect = stackblock();
6457 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006458 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006459 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006460 idx++;
6461 len++;
6462 STPUTC(*idx, expdest);
6463 }
6464 if (stackblock() != restart_detect)
6465 goto restart;
6466 idx++;
6467 len++;
6468 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006469 /* continue; - prone to quadratic behavior, smarter code: */
6470 if (idx >= end)
6471 break;
6472 if (str[0] == '*') {
6473 /* Pattern is "*foo". If "*foo" does not match "long_string",
6474 * it would never match "ong_string" etc, no point in trying.
6475 */
6476 goto skip_matching;
6477 }
6478 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006479 }
6480
6481 if (subtype == VSREPLACEALL) {
6482 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006483 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006484 idx++;
6485 idx++;
6486 rmesc++;
6487 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006488 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006489 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006490 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006491
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006492 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006493 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006494 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006495 if (quotes && *loc == '\\') {
6496 STPUTC(CTLESC, expdest);
6497 len++;
6498 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006499 STPUTC(*loc, expdest);
6500 if (stackblock() != restart_detect)
6501 goto restart;
6502 len++;
6503 }
6504
6505 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006506 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006507 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006508 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006509 STPUTC(*idx, expdest);
6510 if (stackblock() != restart_detect)
6511 goto restart;
6512 len++;
6513 idx++;
6514 }
6515 break;
6516 }
6517 }
6518
6519 /* We've put the replaced text into a buffer at workloc, now
6520 * move it to the right place and adjust the stack.
6521 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006522 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006523 startp = (char *)stackblock() + startloc;
6524 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006525 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006526 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006527 STADJUST(-amount, expdest);
6528 return startp;
6529 }
6530#endif /* ENABLE_ASH_BASH_COMPAT */
6531
6532 subtype -= VSTRIMRIGHT;
6533#if DEBUG
6534 if (subtype < 0 || subtype > 7)
6535 abort();
6536#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006537 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006538 zero = subtype >> 1;
6539 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6540 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6541
6542 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6543 if (loc) {
6544 if (zero) {
6545 memmove(startp, loc, str - loc);
6546 loc = startp + (str - loc) - 1;
6547 }
6548 *loc = '\0';
6549 amount = loc - expdest;
6550 STADJUST(amount, expdest);
6551 }
6552 return loc;
6553}
6554
6555/*
6556 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006557 * name parameter (examples):
6558 * ash -c 'echo $1' name:'1='
6559 * ash -c 'echo $qwe' name:'qwe='
6560 * ash -c 'echo $$' name:'$='
6561 * ash -c 'echo ${$}' name:'$='
6562 * ash -c 'echo ${$##q}' name:'$=q'
6563 * ash -c 'echo ${#$}' name:'$='
6564 * note: examples with bad shell syntax:
6565 * ash -c 'echo ${#$1}' name:'$=1'
6566 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006567 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006568static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006569varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006570{
Mike Frysinger98c52642009-04-02 10:02:37 +00006571 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006572 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006573 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006574 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006575 int sep;
Ron Yorston549deab2015-05-18 09:57:51 +02006576 int quoted = flags & EXP_QUOTED;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006577 int subtype = varflags & VSTYPE;
6578 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6579 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006580 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006581
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006582 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
6583
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006584 switch (*name) {
6585 case '$':
6586 num = rootpid;
6587 goto numvar;
6588 case '?':
6589 num = exitstatus;
6590 goto numvar;
6591 case '#':
6592 num = shellparam.nparam;
6593 goto numvar;
6594 case '!':
6595 num = backgndpid;
6596 if (num == 0)
6597 return -1;
6598 numvar:
6599 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006600 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006601 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006602 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006603 for (i = NOPTS - 1; i >= 0; i--) {
6604 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006605 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006606 len++;
6607 }
6608 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006609 check_1char_name:
6610#if 0
6611 /* handles cases similar to ${#$1} */
6612 if (name[2] != '\0')
6613 raise_error_syntax("bad substitution");
6614#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006615 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006616 case '@': {
6617 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006618 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006619
6620 if (quoted && (flags & EXP_FULL)) {
6621 /* note: this is not meant as PEOF value */
6622 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006623 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006624 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006625 /* fall through */
6626 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006627 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006628 param:
6629 ap = shellparam.p;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006630 sepc = sep;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006631 if (!ap)
6632 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006633 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006634 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006635
6636 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006637 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006638 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006639 }
6640 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006641 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006642 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006643 case '0':
6644 case '1':
6645 case '2':
6646 case '3':
6647 case '4':
6648 case '5':
6649 case '6':
6650 case '7':
6651 case '8':
6652 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006653 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006654 if (num < 0 || num > shellparam.nparam)
6655 return -1;
6656 p = num ? shellparam.p[num - 1] : arg0;
6657 goto value;
6658 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006659 /* NB: name has form "VAR=..." */
6660
6661 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6662 * which should be considered before we check variables. */
6663 if (var_str_list) {
6664 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6665 p = NULL;
6666 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006667 char *str, *eq;
6668 str = var_str_list->text;
6669 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006670 if (!eq) /* stop at first non-assignment */
6671 break;
6672 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006673 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006674 && strncmp(str, name, name_len) == 0
6675 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006676 p = eq;
6677 /* goto value; - WRONG! */
6678 /* think "A=1 A=2 B=$A" */
6679 }
6680 var_str_list = var_str_list->next;
6681 } while (var_str_list);
6682 if (p)
6683 goto value;
6684 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006685 p = lookupvar(name);
6686 value:
6687 if (!p)
6688 return -1;
6689
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006690 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006691#if ENABLE_UNICODE_SUPPORT
6692 if (subtype == VSLENGTH && len > 0) {
6693 reinit_unicode_for_ash();
6694 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006695 STADJUST(-len, expdest);
6696 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006697 len = unicode_strlen(p);
6698 }
6699 }
6700#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006701 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006702 }
6703
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006704 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006705 STADJUST(-len, expdest);
6706 return len;
6707}
6708
6709/*
6710 * Expand a variable, and return a pointer to the next character in the
6711 * input string.
6712 */
6713static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006714evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006715{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006716 char varflags;
6717 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006718 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006719 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006720 char *var;
6721 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006722 int startloc;
6723 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006724
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006725 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006726 subtype = varflags & VSTYPE;
Ron Yorston549deab2015-05-18 09:57:51 +02006727 quoted = flags & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006728 var = p;
6729 easy = (!quoted || (*var == '@' && shellparam.nparam));
6730 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006731 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006732
6733 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006734 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006735 if (varflags & VSNUL)
6736 varlen--;
6737
6738 if (subtype == VSPLUS) {
6739 varlen = -1 - varlen;
6740 goto vsplus;
6741 }
6742
6743 if (subtype == VSMINUS) {
6744 vsplus:
6745 if (varlen < 0) {
6746 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006747 p,
Ron Yorston549deab2015-05-18 09:57:51 +02006748 flags | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006749 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006750 );
6751 goto end;
6752 }
6753 if (easy)
6754 goto record;
6755 goto end;
6756 }
6757
6758 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6759 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006760 if (subevalvar(p, var, /* strloc: */ 0,
6761 subtype, startloc, varflags,
Ron Yorston549deab2015-05-18 09:57:51 +02006762 /* quotes: */ flags & ~QUOTES_ESC,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006763 var_str_list)
6764 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006765 varflags &= ~VSNUL;
6766 /*
6767 * Remove any recorded regions beyond
6768 * start of variable
6769 */
6770 removerecordregions(startloc);
6771 goto again;
6772 }
6773 goto end;
6774 }
6775 if (easy)
6776 goto record;
6777 goto end;
6778 }
6779
6780 if (varlen < 0 && uflag)
6781 varunset(p, var, 0, 0);
6782
6783 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006784 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006785 goto record;
6786 }
6787
6788 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006789 if (easy)
6790 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006791 goto end;
6792 }
6793
6794#if DEBUG
6795 switch (subtype) {
6796 case VSTRIMLEFT:
6797 case VSTRIMLEFTMAX:
6798 case VSTRIMRIGHT:
6799 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006800#if ENABLE_ASH_BASH_COMPAT
6801 case VSSUBSTR:
6802 case VSREPLACE:
6803 case VSREPLACEALL:
6804#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006805 break;
6806 default:
6807 abort();
6808 }
6809#endif
6810
6811 if (varlen >= 0) {
6812 /*
6813 * Terminate the string and start recording the pattern
6814 * right after it
6815 */
6816 STPUTC('\0', expdest);
6817 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006818 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006819 startloc, varflags, flags, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006820 int amount = expdest - (
6821 (char *)stackblock() + patloc - 1
6822 );
6823 STADJUST(-amount, expdest);
6824 }
6825 /* Remove any recorded regions beyond start of variable */
6826 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006827 record:
6828 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006829 }
6830
6831 end:
6832 if (subtype != VSNORMAL) { /* skip to end of alternative */
6833 int nesting = 1;
6834 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006835 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006836 if (c == CTLESC)
6837 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006838 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006839 if (varlen >= 0)
6840 argbackq = argbackq->next;
6841 } else if (c == CTLVAR) {
6842 if ((*p++ & VSTYPE) != VSNORMAL)
6843 nesting++;
6844 } else if (c == CTLENDVAR) {
6845 if (--nesting == 0)
6846 break;
6847 }
6848 }
6849 }
6850 return p;
6851}
6852
6853/*
6854 * Break the argument string into pieces based upon IFS and add the
6855 * strings to the argument list. The regions of the string to be
6856 * searched for IFS characters have been stored by recordregion.
6857 */
6858static void
6859ifsbreakup(char *string, struct arglist *arglist)
6860{
6861 struct ifsregion *ifsp;
6862 struct strlist *sp;
6863 char *start;
6864 char *p;
6865 char *q;
6866 const char *ifs, *realifs;
6867 int ifsspc;
6868 int nulonly;
6869
6870 start = string;
6871 if (ifslastp != NULL) {
6872 ifsspc = 0;
6873 nulonly = 0;
6874 realifs = ifsset() ? ifsval() : defifs;
6875 ifsp = &ifsfirst;
6876 do {
6877 p = string + ifsp->begoff;
6878 nulonly = ifsp->nulonly;
6879 ifs = nulonly ? nullstr : realifs;
6880 ifsspc = 0;
6881 while (p < string + ifsp->endoff) {
6882 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006883 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006884 p++;
6885 if (!strchr(ifs, *p)) {
6886 p++;
6887 continue;
6888 }
6889 if (!nulonly)
6890 ifsspc = (strchr(defifs, *p) != NULL);
6891 /* Ignore IFS whitespace at start */
6892 if (q == start && ifsspc) {
6893 p++;
6894 start = p;
6895 continue;
6896 }
6897 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006898 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006899 sp->text = start;
6900 *arglist->lastp = sp;
6901 arglist->lastp = &sp->next;
6902 p++;
6903 if (!nulonly) {
6904 for (;;) {
6905 if (p >= string + ifsp->endoff) {
6906 break;
6907 }
6908 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006909 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006910 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006911 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006912 p = q;
6913 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006914 }
6915 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006916 if (ifsspc) {
6917 p++;
6918 ifsspc = 0;
6919 } else {
6920 p = q;
6921 break;
6922 }
6923 } else
6924 p++;
6925 }
6926 }
6927 start = p;
6928 } /* while */
6929 ifsp = ifsp->next;
6930 } while (ifsp != NULL);
6931 if (nulonly)
6932 goto add;
6933 }
6934
6935 if (!*start)
6936 return;
6937
6938 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006939 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006940 sp->text = start;
6941 *arglist->lastp = sp;
6942 arglist->lastp = &sp->next;
6943}
6944
6945static void
6946ifsfree(void)
6947{
6948 struct ifsregion *p;
6949
6950 INT_OFF;
6951 p = ifsfirst.next;
6952 do {
6953 struct ifsregion *ifsp;
6954 ifsp = p->next;
6955 free(p);
6956 p = ifsp;
6957 } while (p);
6958 ifslastp = NULL;
6959 ifsfirst.next = NULL;
6960 INT_ON;
6961}
6962
6963/*
6964 * Add a file name to the list.
6965 */
6966static void
6967addfname(const char *name)
6968{
6969 struct strlist *sp;
6970
Denis Vlasenko597906c2008-02-20 16:38:54 +00006971 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006972 sp->text = ststrdup(name);
6973 *exparg.lastp = sp;
6974 exparg.lastp = &sp->next;
6975}
6976
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006977/*
6978 * Do metacharacter (i.e. *, ?, [...]) expansion.
6979 */
6980static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006981expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006982{
6983 char *p;
6984 const char *cp;
6985 char *start;
6986 char *endname;
6987 int metaflag;
6988 struct stat statb;
6989 DIR *dirp;
6990 struct dirent *dp;
6991 int atend;
6992 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01006993 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006994
6995 metaflag = 0;
6996 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01006997 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006998 if (*p == '*' || *p == '?')
6999 metaflag = 1;
7000 else if (*p == '[') {
7001 char *q = p + 1;
7002 if (*q == '!')
7003 q++;
7004 for (;;) {
7005 if (*q == '\\')
7006 q++;
7007 if (*q == '/' || *q == '\0')
7008 break;
7009 if (*++q == ']') {
7010 metaflag = 1;
7011 break;
7012 }
7013 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007014 } else {
7015 if (*p == '\\')
7016 esc++;
7017 if (p[esc] == '/') {
7018 if (metaflag)
7019 break;
7020 start = p + esc + 1;
7021 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007022 }
7023 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007024 if (metaflag == 0) { /* we've reached the end of the file name */
7025 if (enddir != expdir)
7026 metaflag++;
7027 p = name;
7028 do {
7029 if (*p == '\\')
7030 p++;
7031 *enddir++ = *p;
7032 } while (*p++);
7033 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7034 addfname(expdir);
7035 return;
7036 }
7037 endname = p;
7038 if (name < start) {
7039 p = name;
7040 do {
7041 if (*p == '\\')
7042 p++;
7043 *enddir++ = *p++;
7044 } while (p < start);
7045 }
7046 if (enddir == expdir) {
7047 cp = ".";
7048 } else if (enddir == expdir + 1 && *expdir == '/') {
7049 cp = "/";
7050 } else {
7051 cp = expdir;
7052 enddir[-1] = '\0';
7053 }
7054 dirp = opendir(cp);
7055 if (dirp == NULL)
7056 return;
7057 if (enddir != expdir)
7058 enddir[-1] = '/';
7059 if (*endname == 0) {
7060 atend = 1;
7061 } else {
7062 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007063 *endname = '\0';
7064 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007065 }
7066 matchdot = 0;
7067 p = start;
7068 if (*p == '\\')
7069 p++;
7070 if (*p == '.')
7071 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007072 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007073 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007074 continue;
7075 if (pmatch(start, dp->d_name)) {
7076 if (atend) {
7077 strcpy(enddir, dp->d_name);
7078 addfname(expdir);
7079 } else {
7080 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7081 continue;
7082 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007083 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007084 }
7085 }
7086 }
7087 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007088 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007089 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007090}
7091
7092static struct strlist *
7093msort(struct strlist *list, int len)
7094{
7095 struct strlist *p, *q = NULL;
7096 struct strlist **lpp;
7097 int half;
7098 int n;
7099
7100 if (len <= 1)
7101 return list;
7102 half = len >> 1;
7103 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007104 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007105 q = p;
7106 p = p->next;
7107 }
7108 q->next = NULL; /* terminate first half of list */
7109 q = msort(list, half); /* sort first half of list */
7110 p = msort(p, len - half); /* sort second half */
7111 lpp = &list;
7112 for (;;) {
7113#if ENABLE_LOCALE_SUPPORT
7114 if (strcoll(p->text, q->text) < 0)
7115#else
7116 if (strcmp(p->text, q->text) < 0)
7117#endif
7118 {
7119 *lpp = p;
7120 lpp = &p->next;
7121 p = *lpp;
7122 if (p == NULL) {
7123 *lpp = q;
7124 break;
7125 }
7126 } else {
7127 *lpp = q;
7128 lpp = &q->next;
7129 q = *lpp;
7130 if (q == NULL) {
7131 *lpp = p;
7132 break;
7133 }
7134 }
7135 }
7136 return list;
7137}
7138
7139/*
7140 * Sort the results of file name expansion. It calculates the number of
7141 * strings to sort and then calls msort (short for merge sort) to do the
7142 * work.
7143 */
7144static struct strlist *
7145expsort(struct strlist *str)
7146{
7147 int len;
7148 struct strlist *sp;
7149
7150 len = 0;
7151 for (sp = str; sp; sp = sp->next)
7152 len++;
7153 return msort(str, len);
7154}
7155
7156static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007157expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007158{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007159 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007160 '*', '?', '[', 0
7161 };
7162 /* TODO - EXP_REDIR */
7163
7164 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007165 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007166 struct strlist **savelastp;
7167 struct strlist *sp;
7168 char *p;
7169
7170 if (fflag)
7171 goto nometa;
7172 if (!strpbrk(str->text, metachars))
7173 goto nometa;
7174 savelastp = exparg.lastp;
7175
7176 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007177 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007178 {
7179 int i = strlen(str->text);
7180 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7181 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007182 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007183 free(expdir);
7184 if (p != str->text)
7185 free(p);
7186 INT_ON;
7187 if (exparg.lastp == savelastp) {
7188 /*
7189 * no matches
7190 */
7191 nometa:
7192 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007193 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007194 exparg.lastp = &str->next;
7195 } else {
7196 *exparg.lastp = NULL;
7197 *savelastp = sp = expsort(*savelastp);
7198 while (sp->next != NULL)
7199 sp = sp->next;
7200 exparg.lastp = &sp->next;
7201 }
7202 str = str->next;
7203 }
7204}
7205
7206/*
7207 * Perform variable substitution and command substitution on an argument,
7208 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7209 * perform splitting and file name expansion. When arglist is NULL, perform
7210 * here document expansion.
7211 */
7212static void
7213expandarg(union node *arg, struct arglist *arglist, int flag)
7214{
7215 struct strlist *sp;
7216 char *p;
7217
7218 argbackq = arg->narg.backquote;
7219 STARTSTACKSTR(expdest);
7220 ifsfirst.next = NULL;
7221 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007222 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007223 argstr(arg->narg.text, flag,
7224 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007225 p = _STPUTC('\0', expdest);
7226 expdest = p - 1;
7227 if (arglist == NULL) {
7228 return; /* here document expanded */
7229 }
7230 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007231 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007232 exparg.lastp = &exparg.list;
7233 /*
7234 * TODO - EXP_REDIR
7235 */
7236 if (flag & EXP_FULL) {
7237 ifsbreakup(p, &exparg);
7238 *exparg.lastp = NULL;
7239 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007240 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007241 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007242 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007243 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007244 TRACE(("expandarg: rmescapes:'%s'\n", p));
7245 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007246 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007247 sp->text = p;
7248 *exparg.lastp = sp;
7249 exparg.lastp = &sp->next;
7250 }
7251 if (ifsfirst.next)
7252 ifsfree();
7253 *exparg.lastp = NULL;
7254 if (exparg.list) {
7255 *arglist->lastp = exparg.list;
7256 arglist->lastp = exparg.lastp;
7257 }
7258}
7259
7260/*
7261 * Expand shell variables and backquotes inside a here document.
7262 */
7263static void
7264expandhere(union node *arg, int fd)
7265{
7266 herefd = fd;
Ron Yorston549deab2015-05-18 09:57:51 +02007267 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007268 full_write(fd, stackblock(), expdest - (char *)stackblock());
7269}
7270
7271/*
7272 * Returns true if the pattern matches the string.
7273 */
7274static int
7275patmatch(char *pattern, const char *string)
7276{
Ron Yorston549deab2015-05-18 09:57:51 +02007277 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007278}
7279
7280/*
7281 * See if a pattern matches in a case statement.
7282 */
7283static int
7284casematch(union node *pattern, char *val)
7285{
7286 struct stackmark smark;
7287 int result;
7288
7289 setstackmark(&smark);
7290 argbackq = pattern->narg.backquote;
7291 STARTSTACKSTR(expdest);
7292 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007293 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7294 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007295 STACKSTRNUL(expdest);
7296 result = patmatch(stackblock(), val);
7297 popstackmark(&smark);
7298 return result;
7299}
7300
7301
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007302/* ============ find_command */
7303
7304struct builtincmd {
7305 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007306 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007307 /* unsigned flags; */
7308};
7309#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007310/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007311 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007312#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007313#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007314
7315struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007316 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007317 union param {
7318 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007319 /* index >= 0 for commands without path (slashes) */
7320 /* (TODO: what exactly does the value mean? PATH position?) */
7321 /* index == -1 for commands with slashes */
7322 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007323 const struct builtincmd *cmd;
7324 struct funcnode *func;
7325 } u;
7326};
7327/* values of cmdtype */
7328#define CMDUNKNOWN -1 /* no entry in table for command */
7329#define CMDNORMAL 0 /* command is an executable program */
7330#define CMDFUNCTION 1 /* command is a shell function */
7331#define CMDBUILTIN 2 /* command is a shell builtin */
7332
7333/* action to find_command() */
7334#define DO_ERR 0x01 /* prints errors */
7335#define DO_ABS 0x02 /* checks absolute paths */
7336#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7337#define DO_ALTPATH 0x08 /* using alternate path */
7338#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7339
7340static void find_command(char *, struct cmdentry *, int, const char *);
7341
7342
7343/* ============ Hashing commands */
7344
7345/*
7346 * When commands are first encountered, they are entered in a hash table.
7347 * This ensures that a full path search will not have to be done for them
7348 * on each invocation.
7349 *
7350 * We should investigate converting to a linear search, even though that
7351 * would make the command name "hash" a misnomer.
7352 */
7353
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007354struct tblentry {
7355 struct tblentry *next; /* next entry in hash chain */
7356 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007357 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007358 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007359 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007360};
7361
Denis Vlasenko01631112007-12-16 17:20:38 +00007362static struct tblentry **cmdtable;
7363#define INIT_G_cmdtable() do { \
7364 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7365} while (0)
7366
7367static int builtinloc = -1; /* index in path of %builtin, or -1 */
7368
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007369
7370static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007371tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007372{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007373#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007374 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007375 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007376 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007377 while (*envp)
7378 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007379 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007380 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007381 /* re-exec ourselves with the new arguments */
7382 execve(bb_busybox_exec_path, argv, envp);
7383 /* If they called chroot or otherwise made the binary no longer
7384 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007385 }
7386#endif
7387
7388 repeat:
7389#ifdef SYSV
7390 do {
7391 execve(cmd, argv, envp);
7392 } while (errno == EINTR);
7393#else
7394 execve(cmd, argv, envp);
7395#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007396 if (cmd == (char*) bb_busybox_exec_path) {
7397 /* We already visited ENOEXEC branch below, don't do it again */
7398//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007399 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007400 return;
7401 }
7402 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007403 /* Run "cmd" as a shell script:
7404 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7405 * "If the execve() function fails with ENOEXEC, the shell
7406 * shall execute a command equivalent to having a shell invoked
7407 * with the command name as its first operand,
7408 * with any remaining arguments passed to the new shell"
7409 *
7410 * That is, do not use $SHELL, user's shell, or /bin/sh;
7411 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007412 *
7413 * Note that bash reads ~80 chars of the file, and if it sees
7414 * a zero byte before it sees newline, it doesn't try to
7415 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007416 * message and exit code 126. For one, this prevents attempts
7417 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007418 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007419 char **ap;
7420 char **new;
7421
7422 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007423 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007424 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7425 new[0] = (char*) "ash";
7426 new[1] = cmd;
7427 ap = new + 2;
7428 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007429 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007430 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007431 argv = new;
7432 goto repeat;
7433 }
7434}
7435
7436/*
7437 * Exec a program. Never returns. If you change this routine, you may
7438 * have to change the find_command routine as well.
7439 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007440static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007441static void
7442shellexec(char **argv, const char *path, int idx)
7443{
7444 char *cmdname;
7445 int e;
7446 char **envp;
7447 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007448 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007449
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007450 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007451 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007452 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007453#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007454 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007455#endif
7456 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007457 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007458 if (applet_no >= 0) {
7459 /* We tried execing ourself, but it didn't work.
7460 * Maybe /proc/self/exe doesn't exist?
7461 * Try $PATH search.
7462 */
7463 goto try_PATH;
7464 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007465 e = errno;
7466 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007467 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007468 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007469 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007470 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007471 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007472 if (errno != ENOENT && errno != ENOTDIR)
7473 e = errno;
7474 }
7475 stunalloc(cmdname);
7476 }
7477 }
7478
7479 /* Map to POSIX errors */
7480 switch (e) {
7481 case EACCES:
7482 exerrno = 126;
7483 break;
7484 case ENOENT:
7485 exerrno = 127;
7486 break;
7487 default:
7488 exerrno = 2;
7489 break;
7490 }
7491 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007492 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7493 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007494 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7495 /* NOTREACHED */
7496}
7497
7498static void
7499printentry(struct tblentry *cmdp)
7500{
7501 int idx;
7502 const char *path;
7503 char *name;
7504
7505 idx = cmdp->param.index;
7506 path = pathval();
7507 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007508 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007509 stunalloc(name);
7510 } while (--idx >= 0);
7511 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7512}
7513
7514/*
7515 * Clear out command entries. The argument specifies the first entry in
7516 * PATH which has changed.
7517 */
7518static void
7519clearcmdentry(int firstchange)
7520{
7521 struct tblentry **tblp;
7522 struct tblentry **pp;
7523 struct tblentry *cmdp;
7524
7525 INT_OFF;
7526 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7527 pp = tblp;
7528 while ((cmdp = *pp) != NULL) {
7529 if ((cmdp->cmdtype == CMDNORMAL &&
7530 cmdp->param.index >= firstchange)
7531 || (cmdp->cmdtype == CMDBUILTIN &&
7532 builtinloc >= firstchange)
7533 ) {
7534 *pp = cmdp->next;
7535 free(cmdp);
7536 } else {
7537 pp = &cmdp->next;
7538 }
7539 }
7540 }
7541 INT_ON;
7542}
7543
7544/*
7545 * Locate a command in the command hash table. If "add" is nonzero,
7546 * add the command to the table if it is not already present. The
7547 * variable "lastcmdentry" is set to point to the address of the link
7548 * pointing to the entry, so that delete_cmd_entry can delete the
7549 * entry.
7550 *
7551 * Interrupts must be off if called with add != 0.
7552 */
7553static struct tblentry **lastcmdentry;
7554
7555static struct tblentry *
7556cmdlookup(const char *name, int add)
7557{
7558 unsigned int hashval;
7559 const char *p;
7560 struct tblentry *cmdp;
7561 struct tblentry **pp;
7562
7563 p = name;
7564 hashval = (unsigned char)*p << 4;
7565 while (*p)
7566 hashval += (unsigned char)*p++;
7567 hashval &= 0x7FFF;
7568 pp = &cmdtable[hashval % CMDTABLESIZE];
7569 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7570 if (strcmp(cmdp->cmdname, name) == 0)
7571 break;
7572 pp = &cmdp->next;
7573 }
7574 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007575 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7576 + strlen(name)
7577 /* + 1 - already done because
7578 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007579 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007580 cmdp->cmdtype = CMDUNKNOWN;
7581 strcpy(cmdp->cmdname, name);
7582 }
7583 lastcmdentry = pp;
7584 return cmdp;
7585}
7586
7587/*
7588 * Delete the command entry returned on the last lookup.
7589 */
7590static void
7591delete_cmd_entry(void)
7592{
7593 struct tblentry *cmdp;
7594
7595 INT_OFF;
7596 cmdp = *lastcmdentry;
7597 *lastcmdentry = cmdp->next;
7598 if (cmdp->cmdtype == CMDFUNCTION)
7599 freefunc(cmdp->param.func);
7600 free(cmdp);
7601 INT_ON;
7602}
7603
7604/*
7605 * Add a new command entry, replacing any existing command entry for
7606 * the same name - except special builtins.
7607 */
7608static void
7609addcmdentry(char *name, struct cmdentry *entry)
7610{
7611 struct tblentry *cmdp;
7612
7613 cmdp = cmdlookup(name, 1);
7614 if (cmdp->cmdtype == CMDFUNCTION) {
7615 freefunc(cmdp->param.func);
7616 }
7617 cmdp->cmdtype = entry->cmdtype;
7618 cmdp->param = entry->u;
7619 cmdp->rehash = 0;
7620}
7621
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007622static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007623hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007624{
7625 struct tblentry **pp;
7626 struct tblentry *cmdp;
7627 int c;
7628 struct cmdentry entry;
7629 char *name;
7630
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007631 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007632 clearcmdentry(0);
7633 return 0;
7634 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007635
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007636 if (*argptr == NULL) {
7637 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7638 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7639 if (cmdp->cmdtype == CMDNORMAL)
7640 printentry(cmdp);
7641 }
7642 }
7643 return 0;
7644 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007645
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007646 c = 0;
7647 while ((name = *argptr) != NULL) {
7648 cmdp = cmdlookup(name, 0);
7649 if (cmdp != NULL
7650 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007651 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7652 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007653 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007654 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007655 find_command(name, &entry, DO_ERR, pathval());
7656 if (entry.cmdtype == CMDUNKNOWN)
7657 c = 1;
7658 argptr++;
7659 }
7660 return c;
7661}
7662
7663/*
7664 * Called when a cd is done. Marks all commands so the next time they
7665 * are executed they will be rehashed.
7666 */
7667static void
7668hashcd(void)
7669{
7670 struct tblentry **pp;
7671 struct tblentry *cmdp;
7672
7673 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7674 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007675 if (cmdp->cmdtype == CMDNORMAL
7676 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007677 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007678 && builtinloc > 0)
7679 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007680 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007681 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007682 }
7683 }
7684}
7685
7686/*
7687 * Fix command hash table when PATH changed.
7688 * Called before PATH is changed. The argument is the new value of PATH;
7689 * pathval() still returns the old value at this point.
7690 * Called with interrupts off.
7691 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007692static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007693changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007694{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007695 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007696 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007697 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007698 int idx_bltin;
7699
7700 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007701 firstchange = 9999; /* assume no change */
7702 idx = 0;
7703 idx_bltin = -1;
7704 for (;;) {
7705 if (*old != *new) {
7706 firstchange = idx;
7707 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007708 || (*old == ':' && *new == '\0')
7709 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007710 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007711 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007712 old = new; /* ignore subsequent differences */
7713 }
7714 if (*new == '\0')
7715 break;
7716 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7717 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007718 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007719 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007720 new++;
7721 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007722 }
7723 if (builtinloc < 0 && idx_bltin >= 0)
7724 builtinloc = idx_bltin; /* zap builtins */
7725 if (builtinloc >= 0 && idx_bltin < 0)
7726 firstchange = 0;
7727 clearcmdentry(firstchange);
7728 builtinloc = idx_bltin;
7729}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007730enum {
7731 TEOF,
7732 TNL,
7733 TREDIR,
7734 TWORD,
7735 TSEMI,
7736 TBACKGND,
7737 TAND,
7738 TOR,
7739 TPIPE,
7740 TLP,
7741 TRP,
7742 TENDCASE,
7743 TENDBQUOTE,
7744 TNOT,
7745 TCASE,
7746 TDO,
7747 TDONE,
7748 TELIF,
7749 TELSE,
7750 TESAC,
7751 TFI,
7752 TFOR,
7753#if ENABLE_ASH_BASH_COMPAT
7754 TFUNCTION,
7755#endif
7756 TIF,
7757 TIN,
7758 TTHEN,
7759 TUNTIL,
7760 TWHILE,
7761 TBEGIN,
7762 TEND
7763};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007764typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007765
7766/* first char is indicating which tokens mark the end of a list */
7767static const char *const tokname_array[] = {
7768 "\1end of file",
7769 "\0newline",
7770 "\0redirection",
7771 "\0word",
7772 "\0;",
7773 "\0&",
7774 "\0&&",
7775 "\0||",
7776 "\0|",
7777 "\0(",
7778 "\1)",
7779 "\1;;",
7780 "\1`",
7781#define KWDOFFSET 13
7782 /* the following are keywords */
7783 "\0!",
7784 "\0case",
7785 "\1do",
7786 "\1done",
7787 "\1elif",
7788 "\1else",
7789 "\1esac",
7790 "\1fi",
7791 "\0for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007792#if ENABLE_ASH_BASH_COMPAT
7793 "\0function",
7794#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007795 "\0if",
7796 "\0in",
7797 "\1then",
7798 "\0until",
7799 "\0while",
7800 "\0{",
7801 "\1}",
7802};
7803
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007804/* Wrapper around strcmp for qsort/bsearch/... */
7805static int
7806pstrcmp(const void *a, const void *b)
7807{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007808 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007809}
7810
7811static const char *const *
7812findkwd(const char *s)
7813{
7814 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007815 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7816 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007817}
7818
7819/*
7820 * Locate and print what a word is...
7821 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007822static int
Ron Yorston3f221112015-08-03 13:47:33 +01007823describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007824{
7825 struct cmdentry entry;
7826 struct tblentry *cmdp;
7827#if ENABLE_ASH_ALIAS
7828 const struct alias *ap;
7829#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007830
7831 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007832
7833 if (describe_command_verbose) {
7834 out1str(command);
7835 }
7836
7837 /* First look at the keywords */
7838 if (findkwd(command)) {
7839 out1str(describe_command_verbose ? " is a shell keyword" : command);
7840 goto out;
7841 }
7842
7843#if ENABLE_ASH_ALIAS
7844 /* Then look at the aliases */
7845 ap = lookupalias(command, 0);
7846 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007847 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007848 out1str("alias ");
7849 printalias(ap);
7850 return 0;
7851 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007852 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007853 goto out;
7854 }
7855#endif
7856 /* Then check if it is a tracked alias */
7857 cmdp = cmdlookup(command, 0);
7858 if (cmdp != NULL) {
7859 entry.cmdtype = cmdp->cmdtype;
7860 entry.u = cmdp->param;
7861 } else {
7862 /* Finally use brute force */
7863 find_command(command, &entry, DO_ABS, path);
7864 }
7865
7866 switch (entry.cmdtype) {
7867 case CMDNORMAL: {
7868 int j = entry.u.index;
7869 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007870 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007871 p = command;
7872 } else {
7873 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007874 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007875 stunalloc(p);
7876 } while (--j >= 0);
7877 }
7878 if (describe_command_verbose) {
7879 out1fmt(" is%s %s",
7880 (cmdp ? " a tracked alias for" : nullstr), p
7881 );
7882 } else {
7883 out1str(p);
7884 }
7885 break;
7886 }
7887
7888 case CMDFUNCTION:
7889 if (describe_command_verbose) {
7890 out1str(" is a shell function");
7891 } else {
7892 out1str(command);
7893 }
7894 break;
7895
7896 case CMDBUILTIN:
7897 if (describe_command_verbose) {
7898 out1fmt(" is a %sshell builtin",
7899 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7900 "special " : nullstr
7901 );
7902 } else {
7903 out1str(command);
7904 }
7905 break;
7906
7907 default:
7908 if (describe_command_verbose) {
7909 out1str(": not found\n");
7910 }
7911 return 127;
7912 }
7913 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01007914 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007915 return 0;
7916}
7917
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007918static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007919typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007920{
Denis Vlasenko46846e22007-05-20 13:08:31 +00007921 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007922 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00007923 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007924
Denis Vlasenko46846e22007-05-20 13:08:31 +00007925 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00007926 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007927 i++;
7928 verbose = 0;
7929 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00007930 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01007931 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007932 }
7933 return err;
7934}
7935
7936#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007937static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007938commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007939{
7940 int c;
7941 enum {
7942 VERIFY_BRIEF = 1,
7943 VERIFY_VERBOSE = 2,
7944 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01007945 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007946
7947 while ((c = nextopt("pvV")) != '\0')
7948 if (c == 'V')
7949 verify |= VERIFY_VERBOSE;
7950 else if (c == 'v')
7951 verify |= VERIFY_BRIEF;
7952#if DEBUG
7953 else if (c != 'p')
7954 abort();
7955#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007956 else
7957 path = bb_default_path;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007958 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7959 if (verify && (*argptr != NULL)) {
Ron Yorston3f221112015-08-03 13:47:33 +01007960 return describe_command(*argptr, path, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007961 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007962
7963 return 0;
7964}
7965#endif
7966
7967
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007968/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00007969
Denis Vlasenko340299a2008-11-21 10:36:36 +00007970static int funcblocksize; /* size of structures in function */
7971static int funcstringsize; /* size of strings in node */
7972static void *funcblock; /* block to allocate function from */
7973static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007974
Eric Andersencb57d552001-06-28 07:25:16 +00007975/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00007976#define EV_EXIT 01 /* exit after evaluating tree */
7977#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersenc470f442003-07-28 09:56:35 +00007978#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00007979
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02007980static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00007981 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
7982 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
7983 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
7984 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7985 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7986 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
7987 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
7988 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
7989 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
7990 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
7991 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
7992 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
7993 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
7994 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
7995 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
7996 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
7997 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00007998#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00007999 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008000#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008001 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8002 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8003 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8004 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8005 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8006 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8007 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8008 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8009 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008010};
8011
8012static void calcsize(union node *n);
8013
8014static void
8015sizenodelist(struct nodelist *lp)
8016{
8017 while (lp) {
8018 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8019 calcsize(lp->n);
8020 lp = lp->next;
8021 }
8022}
8023
8024static void
8025calcsize(union node *n)
8026{
8027 if (n == NULL)
8028 return;
8029 funcblocksize += nodesize[n->type];
8030 switch (n->type) {
8031 case NCMD:
8032 calcsize(n->ncmd.redirect);
8033 calcsize(n->ncmd.args);
8034 calcsize(n->ncmd.assign);
8035 break;
8036 case NPIPE:
8037 sizenodelist(n->npipe.cmdlist);
8038 break;
8039 case NREDIR:
8040 case NBACKGND:
8041 case NSUBSHELL:
8042 calcsize(n->nredir.redirect);
8043 calcsize(n->nredir.n);
8044 break;
8045 case NAND:
8046 case NOR:
8047 case NSEMI:
8048 case NWHILE:
8049 case NUNTIL:
8050 calcsize(n->nbinary.ch2);
8051 calcsize(n->nbinary.ch1);
8052 break;
8053 case NIF:
8054 calcsize(n->nif.elsepart);
8055 calcsize(n->nif.ifpart);
8056 calcsize(n->nif.test);
8057 break;
8058 case NFOR:
8059 funcstringsize += strlen(n->nfor.var) + 1;
8060 calcsize(n->nfor.body);
8061 calcsize(n->nfor.args);
8062 break;
8063 case NCASE:
8064 calcsize(n->ncase.cases);
8065 calcsize(n->ncase.expr);
8066 break;
8067 case NCLIST:
8068 calcsize(n->nclist.body);
8069 calcsize(n->nclist.pattern);
8070 calcsize(n->nclist.next);
8071 break;
8072 case NDEFUN:
8073 case NARG:
8074 sizenodelist(n->narg.backquote);
8075 funcstringsize += strlen(n->narg.text) + 1;
8076 calcsize(n->narg.next);
8077 break;
8078 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008079#if ENABLE_ASH_BASH_COMPAT
8080 case NTO2:
8081#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008082 case NCLOBBER:
8083 case NFROM:
8084 case NFROMTO:
8085 case NAPPEND:
8086 calcsize(n->nfile.fname);
8087 calcsize(n->nfile.next);
8088 break;
8089 case NTOFD:
8090 case NFROMFD:
8091 calcsize(n->ndup.vname);
8092 calcsize(n->ndup.next);
8093 break;
8094 case NHERE:
8095 case NXHERE:
8096 calcsize(n->nhere.doc);
8097 calcsize(n->nhere.next);
8098 break;
8099 case NNOT:
8100 calcsize(n->nnot.com);
8101 break;
8102 };
8103}
8104
8105static char *
8106nodeckstrdup(char *s)
8107{
8108 char *rtn = funcstring;
8109
8110 strcpy(funcstring, s);
8111 funcstring += strlen(s) + 1;
8112 return rtn;
8113}
8114
8115static union node *copynode(union node *);
8116
8117static struct nodelist *
8118copynodelist(struct nodelist *lp)
8119{
8120 struct nodelist *start;
8121 struct nodelist **lpp;
8122
8123 lpp = &start;
8124 while (lp) {
8125 *lpp = funcblock;
8126 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8127 (*lpp)->n = copynode(lp->n);
8128 lp = lp->next;
8129 lpp = &(*lpp)->next;
8130 }
8131 *lpp = NULL;
8132 return start;
8133}
8134
8135static union node *
8136copynode(union node *n)
8137{
8138 union node *new;
8139
8140 if (n == NULL)
8141 return NULL;
8142 new = funcblock;
8143 funcblock = (char *) funcblock + nodesize[n->type];
8144
8145 switch (n->type) {
8146 case NCMD:
8147 new->ncmd.redirect = copynode(n->ncmd.redirect);
8148 new->ncmd.args = copynode(n->ncmd.args);
8149 new->ncmd.assign = copynode(n->ncmd.assign);
8150 break;
8151 case NPIPE:
8152 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008153 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008154 break;
8155 case NREDIR:
8156 case NBACKGND:
8157 case NSUBSHELL:
8158 new->nredir.redirect = copynode(n->nredir.redirect);
8159 new->nredir.n = copynode(n->nredir.n);
8160 break;
8161 case NAND:
8162 case NOR:
8163 case NSEMI:
8164 case NWHILE:
8165 case NUNTIL:
8166 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8167 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8168 break;
8169 case NIF:
8170 new->nif.elsepart = copynode(n->nif.elsepart);
8171 new->nif.ifpart = copynode(n->nif.ifpart);
8172 new->nif.test = copynode(n->nif.test);
8173 break;
8174 case NFOR:
8175 new->nfor.var = nodeckstrdup(n->nfor.var);
8176 new->nfor.body = copynode(n->nfor.body);
8177 new->nfor.args = copynode(n->nfor.args);
8178 break;
8179 case NCASE:
8180 new->ncase.cases = copynode(n->ncase.cases);
8181 new->ncase.expr = copynode(n->ncase.expr);
8182 break;
8183 case NCLIST:
8184 new->nclist.body = copynode(n->nclist.body);
8185 new->nclist.pattern = copynode(n->nclist.pattern);
8186 new->nclist.next = copynode(n->nclist.next);
8187 break;
8188 case NDEFUN:
8189 case NARG:
8190 new->narg.backquote = copynodelist(n->narg.backquote);
8191 new->narg.text = nodeckstrdup(n->narg.text);
8192 new->narg.next = copynode(n->narg.next);
8193 break;
8194 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008195#if ENABLE_ASH_BASH_COMPAT
8196 case NTO2:
8197#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008198 case NCLOBBER:
8199 case NFROM:
8200 case NFROMTO:
8201 case NAPPEND:
8202 new->nfile.fname = copynode(n->nfile.fname);
8203 new->nfile.fd = n->nfile.fd;
8204 new->nfile.next = copynode(n->nfile.next);
8205 break;
8206 case NTOFD:
8207 case NFROMFD:
8208 new->ndup.vname = copynode(n->ndup.vname);
8209 new->ndup.dupfd = n->ndup.dupfd;
8210 new->ndup.fd = n->ndup.fd;
8211 new->ndup.next = copynode(n->ndup.next);
8212 break;
8213 case NHERE:
8214 case NXHERE:
8215 new->nhere.doc = copynode(n->nhere.doc);
8216 new->nhere.fd = n->nhere.fd;
8217 new->nhere.next = copynode(n->nhere.next);
8218 break;
8219 case NNOT:
8220 new->nnot.com = copynode(n->nnot.com);
8221 break;
8222 };
8223 new->type = n->type;
8224 return new;
8225}
8226
8227/*
8228 * Make a copy of a parse tree.
8229 */
8230static struct funcnode *
8231copyfunc(union node *n)
8232{
8233 struct funcnode *f;
8234 size_t blocksize;
8235
8236 funcblocksize = offsetof(struct funcnode, n);
8237 funcstringsize = 0;
8238 calcsize(n);
8239 blocksize = funcblocksize;
8240 f = ckmalloc(blocksize + funcstringsize);
8241 funcblock = (char *) f + offsetof(struct funcnode, n);
8242 funcstring = (char *) f + blocksize;
8243 copynode(n);
8244 f->count = 0;
8245 return f;
8246}
8247
8248/*
8249 * Define a shell function.
8250 */
8251static void
8252defun(char *name, union node *func)
8253{
8254 struct cmdentry entry;
8255
8256 INT_OFF;
8257 entry.cmdtype = CMDFUNCTION;
8258 entry.u.func = copyfunc(func);
8259 addcmdentry(name, &entry);
8260 INT_ON;
8261}
8262
Denis Vlasenko4b875702009-03-19 13:30:04 +00008263/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008264#define SKIPBREAK (1 << 0)
8265#define SKIPCONT (1 << 1)
8266#define SKIPFUNC (1 << 2)
8267#define SKIPFILE (1 << 3)
8268#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008269static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008270static int skipcount; /* number of levels to skip */
8271static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008272static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008273
Denis Vlasenko4b875702009-03-19 13:30:04 +00008274/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008275static int evalstring(char *s, int mask);
8276
Denis Vlasenko4b875702009-03-19 13:30:04 +00008277/* Called to execute a trap.
8278 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008279 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008280 *
8281 * Perhaps we should avoid entering new trap handlers
8282 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008283 */
8284static int
8285dotrap(void)
8286{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008287 uint8_t *g;
8288 int sig;
8289 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008290
8291 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008292 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008293 xbarrier();
8294
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008295 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008296 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8297 int want_exexit;
8298 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008299
Denis Vlasenko4b875702009-03-19 13:30:04 +00008300 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008301 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008302 t = trap[sig];
8303 /* non-trapped SIGINT is handled separately by raise_interrupt,
8304 * don't upset it by resetting gotsig[SIGINT-1] */
8305 if (sig == SIGINT && !t)
8306 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008307
8308 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008309 *g = 0;
8310 if (!t)
8311 continue;
8312 want_exexit = evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008313 exitstatus = savestatus;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008314 if (want_exexit) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008315 TRACE(("dotrap returns %d\n", want_exexit));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008316 return want_exexit;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008317 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008318 }
8319
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008320 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008321 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008322}
8323
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008324/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008325static void evalloop(union node *, int);
8326static void evalfor(union node *, int);
8327static void evalcase(union node *, int);
8328static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008329static void expredir(union node *);
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008330static void evalpipe(union node *, int);
8331static void evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008332static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008333static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008334
Eric Andersen62483552001-07-10 06:09:16 +00008335/*
Eric Andersenc470f442003-07-28 09:56:35 +00008336 * Evaluate a parse tree. The value is left in the global variable
8337 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008338 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008339static void
Eric Andersenc470f442003-07-28 09:56:35 +00008340evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008341{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008342 struct jmploc *volatile savehandler = exception_handler;
8343 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008344 int checkexit = 0;
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008345 void (*evalfn)(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008346 int status;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008347 int int_level;
8348
8349 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008350
Eric Andersenc470f442003-07-28 09:56:35 +00008351 if (n == NULL) {
8352 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008353 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008354 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008355 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008356
8357 exception_handler = &jmploc;
8358 {
8359 int err = setjmp(jmploc.loc);
8360 if (err) {
8361 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008362 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008363 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8364 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008365 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008366 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008367 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008368 TRACE(("exception %d in evaltree, propagating err=%d\n",
8369 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008370 exception_handler = savehandler;
8371 longjmp(exception_handler->loc, err);
8372 }
8373 }
8374
Eric Andersenc470f442003-07-28 09:56:35 +00008375 switch (n->type) {
8376 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008377#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008378 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008379 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008380 break;
8381#endif
8382 case NNOT:
8383 evaltree(n->nnot.com, EV_TESTED);
8384 status = !exitstatus;
8385 goto setstatus;
8386 case NREDIR:
8387 expredir(n->nredir.redirect);
8388 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8389 if (!status) {
8390 evaltree(n->nredir.n, flags & EV_TESTED);
8391 status = exitstatus;
8392 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008393 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008394 goto setstatus;
8395 case NCMD:
8396 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008397 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008398 if (eflag && !(flags & EV_TESTED))
8399 checkexit = ~0;
8400 goto calleval;
8401 case NFOR:
8402 evalfn = evalfor;
8403 goto calleval;
8404 case NWHILE:
8405 case NUNTIL:
8406 evalfn = evalloop;
8407 goto calleval;
8408 case NSUBSHELL:
8409 case NBACKGND:
8410 evalfn = evalsubshell;
8411 goto calleval;
8412 case NPIPE:
8413 evalfn = evalpipe;
8414 goto checkexit;
8415 case NCASE:
8416 evalfn = evalcase;
8417 goto calleval;
8418 case NAND:
8419 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008420 case NSEMI: {
8421
Eric Andersenc470f442003-07-28 09:56:35 +00008422#if NAND + 1 != NOR
8423#error NAND + 1 != NOR
8424#endif
8425#if NOR + 1 != NSEMI
8426#error NOR + 1 != NSEMI
8427#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008428 unsigned is_or = n->type - NAND;
Eric Andersenc470f442003-07-28 09:56:35 +00008429 evaltree(
8430 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008431 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008432 );
Cristian Ionescu-Idbohrnc2a26252016-01-02 00:52:29 +01008433 if ((!exitstatus) == is_or)
Eric Andersenc470f442003-07-28 09:56:35 +00008434 break;
8435 if (!evalskip) {
8436 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008437 evaln:
Eric Andersenc470f442003-07-28 09:56:35 +00008438 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008439 calleval:
Eric Andersenc470f442003-07-28 09:56:35 +00008440 evalfn(n, flags);
8441 break;
8442 }
8443 break;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008444 }
Eric Andersenc470f442003-07-28 09:56:35 +00008445 case NIF:
8446 evaltree(n->nif.test, EV_TESTED);
8447 if (evalskip)
8448 break;
8449 if (exitstatus == 0) {
8450 n = n->nif.ifpart;
8451 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008452 }
8453 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008454 n = n->nif.elsepart;
8455 goto evaln;
8456 }
8457 goto success;
8458 case NDEFUN:
8459 defun(n->narg.text, n->narg.next);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008460 success:
Eric Andersenc470f442003-07-28 09:56:35 +00008461 status = 0;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008462 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008463 exitstatus = status;
8464 break;
8465 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008466
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008467 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008468 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008469
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008470 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008471 /* Order of checks below is important:
8472 * signal handlers trigger before exit caused by "set -e".
8473 */
8474 if (pending_sig && dotrap())
8475 goto exexit;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008476 if (checkexit & exitstatus)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008477 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008478
8479 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008480 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008481 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008482 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008483
8484 RESTORE_INT(int_level);
8485 TRACE(("leaving evaltree (no interrupts)\n"));
Eric Andersen62483552001-07-10 06:09:16 +00008486}
8487
Eric Andersenc470f442003-07-28 09:56:35 +00008488#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8489static
8490#endif
8491void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8492
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008493static void
Eric Andersenc470f442003-07-28 09:56:35 +00008494evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008495{
8496 int status;
8497
8498 loopnest++;
8499 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008500 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008501 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008502 int i;
8503
Eric Andersencb57d552001-06-28 07:25:16 +00008504 evaltree(n->nbinary.ch1, EV_TESTED);
8505 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008506 skipping:
8507 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008508 evalskip = 0;
8509 continue;
8510 }
8511 if (evalskip == SKIPBREAK && --skipcount <= 0)
8512 evalskip = 0;
8513 break;
8514 }
Eric Andersenc470f442003-07-28 09:56:35 +00008515 i = exitstatus;
8516 if (n->type != NWHILE)
8517 i = !i;
8518 if (i != 0)
8519 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008520 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008521 status = exitstatus;
8522 if (evalskip)
8523 goto skipping;
8524 }
8525 loopnest--;
8526 exitstatus = status;
8527}
8528
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008529static void
Eric Andersenc470f442003-07-28 09:56:35 +00008530evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008531{
8532 struct arglist arglist;
8533 union node *argp;
8534 struct strlist *sp;
8535 struct stackmark smark;
8536
8537 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008538 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008539 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008540 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008541 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008542 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008543 if (evalskip)
8544 goto out;
8545 }
8546 *arglist.lastp = NULL;
8547
8548 exitstatus = 0;
8549 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008550 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008551 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008552 setvar0(n->nfor.var, sp->text);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008553 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008554 if (evalskip) {
8555 if (evalskip == SKIPCONT && --skipcount <= 0) {
8556 evalskip = 0;
8557 continue;
8558 }
8559 if (evalskip == SKIPBREAK && --skipcount <= 0)
8560 evalskip = 0;
8561 break;
8562 }
8563 }
8564 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008565 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008566 popstackmark(&smark);
8567}
8568
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008569static void
Eric Andersenc470f442003-07-28 09:56:35 +00008570evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008571{
8572 union node *cp;
8573 union node *patp;
8574 struct arglist arglist;
8575 struct stackmark smark;
8576
8577 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008578 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008579 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008580 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008581 exitstatus = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008582 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8583 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008584 if (casematch(patp, arglist.list->text)) {
8585 if (evalskip == 0) {
8586 evaltree(cp->nclist.body, flags);
8587 }
8588 goto out;
8589 }
8590 }
8591 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008592 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008593 popstackmark(&smark);
8594}
8595
Eric Andersenc470f442003-07-28 09:56:35 +00008596/*
8597 * Kick off a subshell to evaluate a tree.
8598 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008599static void
Eric Andersenc470f442003-07-28 09:56:35 +00008600evalsubshell(union node *n, int flags)
8601{
8602 struct job *jp;
8603 int backgnd = (n->type == NBACKGND);
8604 int status;
8605
8606 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008607 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008608 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008609 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008610 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008611 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008612 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008613 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008614 flags |= EV_EXIT;
8615 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008616 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008617 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008618 redirect(n->nredir.redirect, 0);
8619 evaltreenr(n->nredir.n, flags);
8620 /* never returns */
8621 }
8622 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008623 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008624 status = waitforjob(jp);
8625 exitstatus = status;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008626 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008627}
8628
Eric Andersenc470f442003-07-28 09:56:35 +00008629/*
8630 * Compute the names of the files in a redirection list.
8631 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008632static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008633static void
8634expredir(union node *n)
8635{
8636 union node *redir;
8637
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008638 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008639 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008640
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008641 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008642 fn.lastp = &fn.list;
8643 switch (redir->type) {
8644 case NFROMTO:
8645 case NFROM:
8646 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008647#if ENABLE_ASH_BASH_COMPAT
8648 case NTO2:
8649#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008650 case NCLOBBER:
8651 case NAPPEND:
8652 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008653 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008654#if ENABLE_ASH_BASH_COMPAT
8655 store_expfname:
8656#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008657#if 0
8658// By the design of stack allocator, the loop of this kind:
8659// while true; do while true; do break; done </dev/null; done
8660// will look like a memory leak: ash plans to free expfname's
8661// of "/dev/null" as soon as it finishes running the loop
8662// (in this case, never).
8663// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008664 if (redir->nfile.expfname)
8665 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008666// It results in corrupted state of stacked allocations.
8667#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008668 redir->nfile.expfname = fn.list->text;
8669 break;
8670 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008671 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008672 if (redir->ndup.vname) {
8673 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008674 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008675 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008676#if ENABLE_ASH_BASH_COMPAT
8677//FIXME: we used expandarg with different args!
8678 if (!isdigit_str9(fn.list->text)) {
8679 /* >&file, not >&fd */
8680 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8681 ash_msg_and_raise_error("redir error");
8682 redir->type = NTO2;
8683 goto store_expfname;
8684 }
8685#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008686 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008687 }
8688 break;
8689 }
8690 }
8691}
8692
Eric Andersencb57d552001-06-28 07:25:16 +00008693/*
Eric Andersencb57d552001-06-28 07:25:16 +00008694 * Evaluate a pipeline. All the processes in the pipeline are children
8695 * of the process creating the pipeline. (This differs from some versions
8696 * of the shell, which make the last process in a pipeline the parent
8697 * of all the rest.)
8698 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008699static void
Eric Andersenc470f442003-07-28 09:56:35 +00008700evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008701{
8702 struct job *jp;
8703 struct nodelist *lp;
8704 int pipelen;
8705 int prevfd;
8706 int pip[2];
8707
Eric Andersenc470f442003-07-28 09:56:35 +00008708 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008709 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008710 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008711 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008712 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008713 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008714 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008715 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008716 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008717 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008718 pip[1] = -1;
8719 if (lp->next) {
8720 if (pipe(pip) < 0) {
8721 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008722 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008723 }
8724 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008725 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008726 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008727 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008728 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008729 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008730 if (prevfd > 0) {
8731 dup2(prevfd, 0);
8732 close(prevfd);
8733 }
8734 if (pip[1] > 1) {
8735 dup2(pip[1], 1);
8736 close(pip[1]);
8737 }
Eric Andersenc470f442003-07-28 09:56:35 +00008738 evaltreenr(lp->n, flags);
8739 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008740 }
8741 if (prevfd >= 0)
8742 close(prevfd);
8743 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008744 /* Don't want to trigger debugging */
8745 if (pip[1] != -1)
8746 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008747 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008748 if (n->npipe.pipe_backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008749 exitstatus = waitforjob(jp);
8750 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00008751 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008752 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008753}
8754
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008755/*
8756 * Controls whether the shell is interactive or not.
8757 */
8758static void
8759setinteractive(int on)
8760{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008761 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008762
8763 if (++on == is_interactive)
8764 return;
8765 is_interactive = on;
8766 setsignal(SIGINT);
8767 setsignal(SIGQUIT);
8768 setsignal(SIGTERM);
8769#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8770 if (is_interactive > 1) {
8771 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008772 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008773
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008774 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008775 /* note: ash and hush share this string */
8776 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008777 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8778 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008779 bb_banner,
8780 "built-in shell (ash)"
8781 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008782 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008783 }
8784 }
8785#endif
8786}
8787
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008788static void
8789optschanged(void)
8790{
8791#if DEBUG
8792 opentrace();
8793#endif
8794 setinteractive(iflag);
8795 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008796#if ENABLE_FEATURE_EDITING_VI
8797 if (viflag)
8798 line_input_state->flags |= VI_MODE;
8799 else
8800 line_input_state->flags &= ~VI_MODE;
8801#else
8802 viflag = 0; /* forcibly keep the option off */
8803#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008804}
8805
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008806static struct localvar *localvars;
8807
8808/*
8809 * Called after a function returns.
8810 * Interrupts must be off.
8811 */
8812static void
8813poplocalvars(void)
8814{
8815 struct localvar *lvp;
8816 struct var *vp;
8817
8818 while ((lvp = localvars) != NULL) {
8819 localvars = lvp->next;
8820 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008821 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008822 if (vp == NULL) { /* $- saved */
8823 memcpy(optlist, lvp->text, sizeof(optlist));
8824 free((char*)lvp->text);
8825 optschanged();
8826 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008827 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008828 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008829 if (vp->var_func)
8830 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008831 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008832 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008833 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008834 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008835 }
8836 free(lvp);
8837 }
8838}
8839
8840static int
8841evalfun(struct funcnode *func, int argc, char **argv, int flags)
8842{
8843 volatile struct shparam saveparam;
8844 struct localvar *volatile savelocalvars;
8845 struct jmploc *volatile savehandler;
8846 struct jmploc jmploc;
8847 int e;
8848
8849 saveparam = shellparam;
8850 savelocalvars = localvars;
8851 e = setjmp(jmploc.loc);
8852 if (e) {
8853 goto funcdone;
8854 }
8855 INT_OFF;
8856 savehandler = exception_handler;
8857 exception_handler = &jmploc;
8858 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008859 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008860 func->count++;
8861 funcnest++;
8862 INT_ON;
8863 shellparam.nparam = argc - 1;
8864 shellparam.p = argv + 1;
8865#if ENABLE_ASH_GETOPTS
8866 shellparam.optind = 1;
8867 shellparam.optoff = -1;
8868#endif
8869 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008870 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008871 INT_OFF;
8872 funcnest--;
8873 freefunc(func);
8874 poplocalvars();
8875 localvars = savelocalvars;
8876 freeparam(&shellparam);
8877 shellparam = saveparam;
8878 exception_handler = savehandler;
8879 INT_ON;
8880 evalskip &= ~SKIPFUNC;
8881 return e;
8882}
8883
Denis Vlasenko131ae172007-02-18 13:00:19 +00008884#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008885static char **
8886parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008887{
8888 char *cp, c;
8889
8890 for (;;) {
8891 cp = *++argv;
8892 if (!cp)
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008893 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008894 if (*cp++ != '-')
8895 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008896 c = *cp++;
8897 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008898 break;
8899 if (c == '-' && !*cp) {
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008900 if (!*++argv)
8901 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008902 break;
8903 }
8904 do {
8905 switch (c) {
8906 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00008907 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00008908 break;
8909 default:
8910 /* run 'typecmd' for other options */
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008911 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008912 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00008913 c = *cp++;
8914 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00008915 }
8916 return argv;
8917}
8918#endif
8919
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008920/*
8921 * Make a variable a local variable. When a variable is made local, it's
8922 * value and flags are saved in a localvar structure. The saved values
8923 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02008924 * "-" as a special case: it makes changes to "set +-options" local
8925 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008926 */
8927static void
8928mklocal(char *name)
8929{
8930 struct localvar *lvp;
8931 struct var **vpp;
8932 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008933 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008934
8935 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008936 /* Cater for duplicate "local". Examples:
8937 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
8938 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
8939 */
8940 lvp = localvars;
8941 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02008942 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008943 if (eq)
8944 setvareq(name, 0);
8945 /* else:
8946 * it's a duplicate "local VAR" declaration, do nothing
8947 */
8948 return;
8949 }
8950 lvp = lvp->next;
8951 }
8952
8953 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008954 if (LONE_DASH(name)) {
8955 char *p;
8956 p = ckmalloc(sizeof(optlist));
8957 lvp->text = memcpy(p, optlist, sizeof(optlist));
8958 vp = NULL;
8959 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008960 vpp = hashvar(name);
8961 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008962 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008963 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008964 if (eq)
8965 setvareq(name, VSTRFIXED);
8966 else
8967 setvar(name, NULL, VSTRFIXED);
8968 vp = *vpp; /* the new variable */
8969 lvp->flags = VUNSET;
8970 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008971 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008972 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008973 /* make sure neither "struct var" nor string gets freed
8974 * during (un)setting:
8975 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008976 vp->flags |= VSTRFIXED|VTEXTFIXED;
8977 if (eq)
8978 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01008979 else
8980 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008981 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008982 }
8983 }
8984 lvp->vp = vp;
8985 lvp->next = localvars;
8986 localvars = lvp;
8987 INT_ON;
8988}
8989
8990/*
8991 * The "local" command.
8992 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008993static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008994localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008995{
8996 char *name;
8997
Ron Yorstonef2386b2015-10-29 16:19:14 +00008998 if (!funcnest)
8999 ash_msg_and_raise_error("not in a function");
9000
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009001 argv = argptr;
9002 while ((name = *argv++) != NULL) {
9003 mklocal(name);
9004 }
9005 return 0;
9006}
9007
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009008static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009009falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009010{
9011 return 1;
9012}
9013
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009014static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009015truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009016{
9017 return 0;
9018}
9019
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009020static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009021execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009022{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009023 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009024 iflag = 0; /* exit on error */
9025 mflag = 0;
9026 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009027 /* We should set up signals for "exec CMD"
9028 * the same way as for "CMD" without "exec".
9029 * But optschanged->setinteractive->setsignal
9030 * still thought we are a root shell. Therefore, for example,
9031 * SIGQUIT is still set to IGN. Fix it:
9032 */
9033 shlvl++;
9034 setsignal(SIGQUIT);
9035 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9036 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9037 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9038
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009039 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009040 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009041 }
9042 return 0;
9043}
9044
9045/*
9046 * The return command.
9047 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009048static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009049returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009050{
9051 /*
9052 * If called outside a function, do what ksh does;
9053 * skip the rest of the file.
9054 */
9055 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9056 return argv[1] ? number(argv[1]) : exitstatus;
9057}
9058
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009059/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009060static int breakcmd(int, char **) FAST_FUNC;
9061static int dotcmd(int, char **) FAST_FUNC;
9062static int evalcmd(int, char **) FAST_FUNC;
9063static int exitcmd(int, char **) FAST_FUNC;
9064static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009065#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009066static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009067#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009068#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009069static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009070#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009071#if MAX_HISTORY
9072static int historycmd(int, char **) FAST_FUNC;
9073#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009074#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009075static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009076#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009077static int readcmd(int, char **) FAST_FUNC;
9078static int setcmd(int, char **) FAST_FUNC;
9079static int shiftcmd(int, char **) FAST_FUNC;
9080static int timescmd(int, char **) FAST_FUNC;
9081static int trapcmd(int, char **) FAST_FUNC;
9082static int umaskcmd(int, char **) FAST_FUNC;
9083static int unsetcmd(int, char **) FAST_FUNC;
9084static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009085
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009086#define BUILTIN_NOSPEC "0"
9087#define BUILTIN_SPECIAL "1"
9088#define BUILTIN_REGULAR "2"
9089#define BUILTIN_SPEC_REG "3"
9090#define BUILTIN_ASSIGN "4"
9091#define BUILTIN_SPEC_ASSG "5"
9092#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009093#define BUILTIN_SPEC_REG_ASSG "7"
9094
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009095/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009096#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009097static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009098#endif
9099#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009100static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009101#endif
9102#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009103static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009104#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009105
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009106/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009107static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009108 { BUILTIN_SPEC_REG "." , dotcmd },
9109 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009110#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009111 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009112#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009113 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009114#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009115#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009116#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009117 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009118#endif
9119#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009120 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009121#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009122 { BUILTIN_SPEC_REG "break" , breakcmd },
9123 { BUILTIN_REGULAR "cd" , cdcmd },
9124 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009125#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009126 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009127#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009128 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009129#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009130 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009131#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009132 { BUILTIN_SPEC_REG "eval" , evalcmd },
9133 { BUILTIN_SPEC_REG "exec" , execcmd },
9134 { BUILTIN_SPEC_REG "exit" , exitcmd },
9135 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9136 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009137#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009138 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009139#endif
9140#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009141 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009142#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009143 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009144#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009145 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009146#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009147#if MAX_HISTORY
9148 { BUILTIN_NOSPEC "history" , historycmd },
9149#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009150#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009151 { BUILTIN_REGULAR "jobs" , jobscmd },
9152 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009153#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009154#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009155 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009156#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009157 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009158#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009159 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009160#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009161 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9162 { BUILTIN_REGULAR "read" , readcmd },
9163 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9164 { BUILTIN_SPEC_REG "return" , returncmd },
9165 { BUILTIN_SPEC_REG "set" , setcmd },
9166 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009167#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009168 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009169#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009170#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009171 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009172#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009173 { BUILTIN_SPEC_REG "times" , timescmd },
9174 { BUILTIN_SPEC_REG "trap" , trapcmd },
9175 { BUILTIN_REGULAR "true" , truecmd },
9176 { BUILTIN_NOSPEC "type" , typecmd },
9177 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9178 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009179#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009180 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009181#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009182 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9183 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009184};
9185
Denis Vlasenko80591b02008-03-25 07:49:43 +00009186/* Should match the above table! */
9187#define COMMANDCMD (builtintab + \
9188 2 + \
9189 1 * ENABLE_ASH_BUILTIN_TEST + \
9190 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9191 1 * ENABLE_ASH_ALIAS + \
9192 1 * ENABLE_ASH_JOB_CONTROL + \
9193 3)
9194#define EXECCMD (builtintab + \
9195 2 + \
9196 1 * ENABLE_ASH_BUILTIN_TEST + \
9197 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9198 1 * ENABLE_ASH_ALIAS + \
9199 1 * ENABLE_ASH_JOB_CONTROL + \
9200 3 + \
9201 1 * ENABLE_ASH_CMDCMD + \
9202 1 + \
9203 ENABLE_ASH_BUILTIN_ECHO + \
9204 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009205
9206/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009207 * Search the table of builtin commands.
9208 */
9209static struct builtincmd *
9210find_builtin(const char *name)
9211{
9212 struct builtincmd *bp;
9213
9214 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009215 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009216 pstrcmp
9217 );
9218 return bp;
9219}
9220
9221/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009222 * Execute a simple command.
9223 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009224static int
9225isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009226{
9227 const char *q = endofname(p);
9228 if (p == q)
9229 return 0;
9230 return *q == '=';
9231}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009232static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009233bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009234{
9235 /* Preserve exitstatus of a previous possible redirection
9236 * as POSIX mandates */
9237 return back_exitstatus;
9238}
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02009239static void
Eric Andersenc470f442003-07-28 09:56:35 +00009240evalcommand(union node *cmd, int flags)
9241{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009242 static const struct builtincmd null_bltin = {
9243 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009244 };
Eric Andersenc470f442003-07-28 09:56:35 +00009245 struct stackmark smark;
9246 union node *argp;
9247 struct arglist arglist;
9248 struct arglist varlist;
9249 char **argv;
9250 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009251 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009252 struct cmdentry cmdentry;
9253 struct job *jp;
9254 char *lastarg;
9255 const char *path;
9256 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009257 int status;
9258 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009259 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009260 smallint cmd_is_exec;
9261 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009262
9263 /* First expand the arguments. */
9264 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9265 setstackmark(&smark);
9266 back_exitstatus = 0;
9267
9268 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009269 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009270 varlist.lastp = &varlist.list;
9271 *varlist.lastp = NULL;
9272 arglist.lastp = &arglist.list;
9273 *arglist.lastp = NULL;
9274
9275 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009276 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009277 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9278 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9279 }
9280
Eric Andersenc470f442003-07-28 09:56:35 +00009281 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9282 struct strlist **spp;
9283
9284 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009285 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009286 expandarg(argp, &arglist, EXP_VARTILDE);
9287 else
9288 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9289
Eric Andersenc470f442003-07-28 09:56:35 +00009290 for (sp = *spp; sp; sp = sp->next)
9291 argc++;
9292 }
9293
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009294 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009295 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009296 TRACE(("evalcommand arg: %s\n", sp->text));
9297 *nargv++ = sp->text;
9298 }
9299 *nargv = NULL;
9300
9301 lastarg = NULL;
9302 if (iflag && funcnest == 0 && argc > 0)
9303 lastarg = nargv[-1];
9304
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009305 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009306 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009307 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009308
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009309 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009310 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9311 struct strlist **spp;
9312 char *p;
9313
9314 spp = varlist.lastp;
9315 expandarg(argp, &varlist, EXP_VARTILDE);
9316
9317 /*
9318 * Modify the command lookup path, if a PATH= assignment
9319 * is present
9320 */
9321 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009322 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009323 path = p;
9324 }
9325
9326 /* Print the command if xflag is set. */
9327 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009328 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009329 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009330
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009331 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009332 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009333 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009334 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009335 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009336 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009337 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009338 }
9339 sp = arglist.list;
9340 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009341 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009342 }
9343
9344 cmd_is_exec = 0;
9345 spclbltin = -1;
9346
9347 /* Now locate the command. */
9348 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009349 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009350#if ENABLE_ASH_CMDCMD
9351 const char *oldpath = path + 5;
9352#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009353 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009354 for (;;) {
9355 find_command(argv[0], &cmdentry, cmd_flag, path);
9356 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009357 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009358 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009359 goto bail;
9360 }
9361
9362 /* implement bltin and command here */
9363 if (cmdentry.cmdtype != CMDBUILTIN)
9364 break;
9365 if (spclbltin < 0)
9366 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9367 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009368 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009369#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009370 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009371 path = oldpath;
9372 nargv = parse_command_args(argv, &path);
9373 if (!nargv)
9374 break;
9375 argc -= nargv - argv;
9376 argv = nargv;
9377 cmd_flag |= DO_NOFUNC;
9378 } else
9379#endif
9380 break;
9381 }
9382 }
9383
9384 if (status) {
9385 /* We have a redirection error. */
9386 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009387 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009388 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009389 exitstatus = status;
9390 goto out;
9391 }
9392
9393 /* Execute the command. */
9394 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009395 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009396
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009397#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009398/* (1) BUG: if variables are set, we need to fork, or save/restore them
9399 * around run_nofork_applet() call.
9400 * (2) Should this check also be done in forkshell()?
9401 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9402 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009403 /* find_command() encodes applet_no as (-2 - applet_no) */
9404 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009405 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009406 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009407 /* run <applet>_main() */
9408 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009409 break;
9410 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009411#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009412 /* Can we avoid forking off? For example, very last command
9413 * in a script or a subshell does not need forking,
9414 * we can just exec it.
9415 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009416 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009417 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009418 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009419 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009420 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009421 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009422 exitstatus = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009423 INT_ON;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009424 TRACE(("forked child exited with %d\n", exitstatus));
Eric Andersenc470f442003-07-28 09:56:35 +00009425 break;
9426 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009427 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009428 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009429 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009430 }
9431 listsetvar(varlist.list, VEXPORT|VSTACK);
9432 shellexec(argv, path, cmdentry.u.index);
9433 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009434 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009435 case CMDBUILTIN:
9436 cmdenviron = varlist.list;
9437 if (cmdenviron) {
9438 struct strlist *list = cmdenviron;
9439 int i = VNOSET;
9440 if (spclbltin > 0 || argc == 0) {
9441 i = 0;
9442 if (cmd_is_exec && argc > 1)
9443 i = VEXPORT;
9444 }
9445 listsetvar(list, i);
9446 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009447 /* Tight loop with builtins only:
9448 * "while kill -0 $child; do true; done"
9449 * will never exit even if $child died, unless we do this
9450 * to reap the zombie and make kill detect that it's gone: */
9451 dowait(DOWAIT_NONBLOCK, NULL);
9452
Eric Andersenc470f442003-07-28 09:56:35 +00009453 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9454 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009455 int i = exception_type;
Ron Yorston8c55dc72015-10-30 19:06:47 +00009456 if (i == EXEXIT || i == EXEXEC)
Eric Andersenc470f442003-07-28 09:56:35 +00009457 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009458 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009459 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009460 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009461 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009462 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009463 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009464 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009465 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009466 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009467 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009468 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009469 }
9470 break;
9471
9472 case CMDFUNCTION:
9473 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009474 /* See above for the rationale */
9475 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009476 if (evalfun(cmdentry.u.func, argc, argv, flags))
9477 goto raise;
9478 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009479 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009480
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009481 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009482 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009483 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009484 /* dsl: I think this is intended to be used to support
9485 * '_' in 'vi' command mode during line editing...
9486 * However I implemented that within libedit itself.
9487 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009488 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009489 }
Eric Andersenc470f442003-07-28 09:56:35 +00009490 popstackmark(&smark);
9491}
9492
9493static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009494evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9495{
Eric Andersenc470f442003-07-28 09:56:35 +00009496 char *volatile savecmdname;
9497 struct jmploc *volatile savehandler;
9498 struct jmploc jmploc;
9499 int i;
9500
9501 savecmdname = commandname;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009502 i = setjmp(jmploc.loc);
9503 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009504 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009505 savehandler = exception_handler;
9506 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009507 commandname = argv[0];
9508 argptr = argv + 1;
9509 optptr = NULL; /* initialize nextopt */
9510 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009511 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009512 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009513 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009514 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009515 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009516 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009517
9518 return i;
9519}
9520
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009521static int
9522goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009523{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009524 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009525}
9526
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009527
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009528/*
9529 * Search for a command. This is called before we fork so that the
9530 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009531 * the child. The check for "goodname" is an overly conservative
9532 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009533 */
Eric Andersenc470f442003-07-28 09:56:35 +00009534static void
9535prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009536{
9537 struct cmdentry entry;
9538
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009539 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9540 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009541}
9542
Eric Andersencb57d552001-06-28 07:25:16 +00009543
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009544/* ============ Builtin commands
9545 *
9546 * Builtin commands whose functions are closely tied to evaluation
9547 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009548 */
9549
9550/*
Eric Andersencb57d552001-06-28 07:25:16 +00009551 * Handle break and continue commands. Break, continue, and return are
9552 * all handled by setting the evalskip flag. The evaluation routines
9553 * above all check this flag, and if it is set they start skipping
9554 * commands rather than executing them. The variable skipcount is
9555 * the number of loops to break/continue, or the number of function
9556 * levels to return. (The latter is always 1.) It should probably
9557 * be an error to break out of more loops than exist, but it isn't
9558 * in the standard shell so we don't make it one here.
9559 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009560static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009561breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009562{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009563 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009564
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009565 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009566 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009567 if (n > loopnest)
9568 n = loopnest;
9569 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009570 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009571 skipcount = n;
9572 }
9573 return 0;
9574}
9575
Eric Andersenc470f442003-07-28 09:56:35 +00009576
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009577/* ============ input.c
9578 *
Eric Andersen90898442003-08-06 11:20:52 +00009579 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009580 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009581
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009582enum {
9583 INPUT_PUSH_FILE = 1,
9584 INPUT_NOFILE_OK = 2,
9585};
Eric Andersencb57d552001-06-28 07:25:16 +00009586
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009587static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009588/* values of checkkwd variable */
9589#define CHKALIAS 0x1
9590#define CHKKWD 0x2
9591#define CHKNL 0x4
9592
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009593/*
9594 * Push a string back onto the input at this current parsefile level.
9595 * We handle aliases this way.
9596 */
9597#if !ENABLE_ASH_ALIAS
9598#define pushstring(s, ap) pushstring(s)
9599#endif
9600static void
9601pushstring(char *s, struct alias *ap)
9602{
9603 struct strpush *sp;
9604 int len;
9605
9606 len = strlen(s);
9607 INT_OFF;
9608 if (g_parsefile->strpush) {
9609 sp = ckzalloc(sizeof(*sp));
9610 sp->prev = g_parsefile->strpush;
9611 } else {
9612 sp = &(g_parsefile->basestrpush);
9613 }
9614 g_parsefile->strpush = sp;
9615 sp->prev_string = g_parsefile->next_to_pgetc;
9616 sp->prev_left_in_line = g_parsefile->left_in_line;
9617#if ENABLE_ASH_ALIAS
9618 sp->ap = ap;
9619 if (ap) {
9620 ap->flag |= ALIASINUSE;
9621 sp->string = s;
9622 }
9623#endif
9624 g_parsefile->next_to_pgetc = s;
9625 g_parsefile->left_in_line = len;
9626 INT_ON;
9627}
9628
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009629static void
9630popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009631{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009632 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009633
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009634 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009635#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009636 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009637 if (g_parsefile->next_to_pgetc[-1] == ' '
9638 || g_parsefile->next_to_pgetc[-1] == '\t'
9639 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009640 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009641 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009642 if (sp->string != sp->ap->val) {
9643 free(sp->string);
9644 }
9645 sp->ap->flag &= ~ALIASINUSE;
9646 if (sp->ap->flag & ALIASDEAD) {
9647 unalias(sp->ap->name);
9648 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009649 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009650#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009651 g_parsefile->next_to_pgetc = sp->prev_string;
9652 g_parsefile->left_in_line = sp->prev_left_in_line;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009653 g_parsefile->strpush = sp->prev;
9654 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009655 free(sp);
9656 INT_ON;
9657}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009658
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009659//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9660//it peeks whether it is &>, and then pushes back both chars.
9661//This function needs to save last *next_to_pgetc to buf[0]
9662//to make two pungetc() reliable. Currently,
9663// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009664static int
9665preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009666{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009667 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009668 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009669
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009670 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009671#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009672 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009673 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009674 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009675 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009676 int timeout = -1;
9677# if ENABLE_ASH_IDLE_TIMEOUT
9678 if (iflag) {
9679 const char *tmout_var = lookupvar("TMOUT");
9680 if (tmout_var) {
9681 timeout = atoi(tmout_var) * 1000;
9682 if (timeout <= 0)
9683 timeout = -1;
9684 }
9685 }
9686# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009687# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009688 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009689# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009690 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009691 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009692 if (nr == 0) {
9693 /* Ctrl+C pressed */
9694 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009695 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009696 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009697 raise(SIGINT);
9698 return 1;
9699 }
Eric Andersenc470f442003-07-28 09:56:35 +00009700 goto retry;
9701 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009702 if (nr < 0) {
9703 if (errno == 0) {
9704 /* Ctrl+D pressed */
9705 nr = 0;
9706 }
9707# if ENABLE_ASH_IDLE_TIMEOUT
9708 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009709 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009710 exitshell();
9711 }
9712# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009713 }
Eric Andersencb57d552001-06-28 07:25:16 +00009714 }
9715#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009716 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009717#endif
9718
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009719#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009720 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009721 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009722 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009723 if (flags >= 0 && (flags & O_NONBLOCK)) {
9724 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009725 if (fcntl(0, F_SETFL, flags) >= 0) {
9726 out2str("sh: turning off NDELAY mode\n");
9727 goto retry;
9728 }
9729 }
9730 }
9731 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009732#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009733 return nr;
9734}
9735
9736/*
9737 * Refill the input buffer and return the next input character:
9738 *
9739 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009740 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9741 * or we are reading from a string so we can't refill the buffer,
9742 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009743 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009744 * 4) Process input up to the next newline, deleting nul characters.
9745 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009746//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9747#define pgetc_debug(...) ((void)0)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009748static int
Eric Andersenc470f442003-07-28 09:56:35 +00009749preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009750{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009751 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009752 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009753
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009754 while (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009755#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009756 if (g_parsefile->left_in_line == -1
9757 && g_parsefile->strpush->ap
9758 && g_parsefile->next_to_pgetc[-1] != ' '
9759 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009760 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009761 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009762 return PEOA;
9763 }
Eric Andersen2870d962001-07-02 17:27:21 +00009764#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009765 popstring();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009766 /* try "pgetc" now: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009767 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9768 g_parsefile->left_in_line,
9769 g_parsefile->next_to_pgetc,
9770 g_parsefile->next_to_pgetc);
9771 if (--g_parsefile->left_in_line >= 0)
9772 return (unsigned char)(*g_parsefile->next_to_pgetc++);
Eric Andersencb57d552001-06-28 07:25:16 +00009773 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009774 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009775 * "pgetc" needs refilling.
9776 */
9777
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009778 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009779 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009780 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009781 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009782 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009783 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009784 /* even in failure keep left_in_line and next_to_pgetc
9785 * in lock step, for correct multi-layer pungetc.
9786 * left_in_line was decremented before preadbuffer(),
9787 * must inc next_to_pgetc: */
9788 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009789 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009790 }
Eric Andersencb57d552001-06-28 07:25:16 +00009791
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009792 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009793 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009794 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009795 again:
9796 more = preadfd();
9797 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009798 /* don't try reading again */
9799 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009800 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009801 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009802 return PEOF;
9803 }
9804 }
9805
Denis Vlasenko727752d2008-11-28 03:41:47 +00009806 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009807 * Set g_parsefile->left_in_line
9808 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009809 * NUL chars are deleted.
9810 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009811 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009812 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009813 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009814
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009815 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009816
Denis Vlasenko727752d2008-11-28 03:41:47 +00009817 c = *q;
9818 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009819 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009820 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009821 q++;
9822 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009823 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009824 break;
9825 }
Eric Andersencb57d552001-06-28 07:25:16 +00009826 }
9827
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009828 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009829 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9830 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009831 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009832 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009833 }
9834 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009835 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009836
Eric Andersencb57d552001-06-28 07:25:16 +00009837 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009838 char save = *q;
9839 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009840 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009841 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009842 }
9843
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009844 pgetc_debug("preadbuffer at %d:%p'%s'",
9845 g_parsefile->left_in_line,
9846 g_parsefile->next_to_pgetc,
9847 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009848 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009849}
9850
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009851#define pgetc_as_macro() \
9852 (--g_parsefile->left_in_line >= 0 \
Denys Vlasenkocd716832009-11-28 22:14:02 +01009853 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009854 : preadbuffer() \
9855 )
Denis Vlasenko727752d2008-11-28 03:41:47 +00009856
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009857static int
9858pgetc(void)
9859{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009860 pgetc_debug("pgetc_fast at %d:%p'%s'",
9861 g_parsefile->left_in_line,
9862 g_parsefile->next_to_pgetc,
9863 g_parsefile->next_to_pgetc);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009864 return pgetc_as_macro();
9865}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009866
9867#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009868# define pgetc_fast() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009869#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009870# define pgetc_fast() pgetc_as_macro()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009871#endif
9872
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009873#if ENABLE_ASH_ALIAS
9874static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009875pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009876{
9877 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009878 do {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009879 pgetc_debug("pgetc_fast at %d:%p'%s'",
9880 g_parsefile->left_in_line,
9881 g_parsefile->next_to_pgetc,
9882 g_parsefile->next_to_pgetc);
Denis Vlasenko834dee72008-10-07 09:18:30 +00009883 c = pgetc_fast();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009884 } while (c == PEOA);
9885 return c;
9886}
9887#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009888# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009889#endif
9890
9891/*
9892 * Read a line from the script.
9893 */
9894static char *
9895pfgets(char *line, int len)
9896{
9897 char *p = line;
9898 int nleft = len;
9899 int c;
9900
9901 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009902 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009903 if (c == PEOF) {
9904 if (p == line)
9905 return NULL;
9906 break;
9907 }
9908 *p++ = c;
9909 if (c == '\n')
9910 break;
9911 }
9912 *p = '\0';
9913 return line;
9914}
9915
Eric Andersenc470f442003-07-28 09:56:35 +00009916/*
9917 * Undo the last call to pgetc. Only one character may be pushed back.
9918 * PEOF may be pushed back.
9919 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009920static void
Eric Andersenc470f442003-07-28 09:56:35 +00009921pungetc(void)
9922{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009923 g_parsefile->left_in_line++;
9924 g_parsefile->next_to_pgetc--;
9925 pgetc_debug("pushed back to %d:%p'%s'",
9926 g_parsefile->left_in_line,
9927 g_parsefile->next_to_pgetc,
9928 g_parsefile->next_to_pgetc);
Eric Andersencb57d552001-06-28 07:25:16 +00009929}
9930
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009931/*
9932 * To handle the "." command, a stack of input files is used. Pushfile
9933 * adds a new entry to the stack and popfile restores the previous level.
9934 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009935static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009936pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009937{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009938 struct parsefile *pf;
9939
Denis Vlasenko597906c2008-02-20 16:38:54 +00009940 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009941 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009942 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +00009943 /*pf->strpush = NULL; - ckzalloc did it */
9944 /*pf->basestrpush.prev = NULL;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009945 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009946}
9947
9948static void
9949popfile(void)
9950{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009951 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +00009952
Denis Vlasenkob012b102007-02-19 22:43:01 +00009953 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009954 if (pf->pf_fd >= 0)
9955 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +00009956 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009957 while (pf->strpush)
9958 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009959 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009960 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009961 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009962}
9963
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009964/*
9965 * Return to top level.
9966 */
9967static void
9968popallfiles(void)
9969{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009970 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009971 popfile();
9972}
9973
9974/*
9975 * Close the file(s) that the shell is reading commands from. Called
9976 * after a fork is done.
9977 */
9978static void
9979closescript(void)
9980{
9981 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009982 if (g_parsefile->pf_fd > 0) {
9983 close(g_parsefile->pf_fd);
9984 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009985 }
9986}
9987
9988/*
9989 * Like setinputfile, but takes an open file descriptor. Call this with
9990 * interrupts off.
9991 */
9992static void
9993setinputfd(int fd, int push)
9994{
Denis Vlasenko96e1b382007-09-30 23:50:48 +00009995 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009996 if (push) {
9997 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009998 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009999 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010000 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010001 if (g_parsefile->buf == NULL)
10002 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010003 g_parsefile->left_in_buffer = 0;
10004 g_parsefile->left_in_line = 0;
10005 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010006}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010007
Eric Andersenc470f442003-07-28 09:56:35 +000010008/*
10009 * Set the input to take input from a file. If push is set, push the
10010 * old input onto the stack first.
10011 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010012static int
10013setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010014{
10015 int fd;
10016 int fd2;
10017
Denis Vlasenkob012b102007-02-19 22:43:01 +000010018 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010019 fd = open(fname, O_RDONLY);
10020 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010021 if (flags & INPUT_NOFILE_OK)
10022 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010023 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010024 }
Eric Andersenc470f442003-07-28 09:56:35 +000010025 if (fd < 10) {
10026 fd2 = copyfd(fd, 10);
10027 close(fd);
10028 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010029 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010030 fd = fd2;
10031 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010032 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010033 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010034 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010035 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010036}
10037
Eric Andersencb57d552001-06-28 07:25:16 +000010038/*
10039 * Like setinputfile, but takes input from a string.
10040 */
Eric Andersenc470f442003-07-28 09:56:35 +000010041static void
10042setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010043{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010044 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010045 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010046 g_parsefile->next_to_pgetc = string;
10047 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010048 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010049 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010050 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010051}
10052
10053
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010054/* ============ mail.c
10055 *
10056 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010057 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010058
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010059#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010060
Denys Vlasenko23841622015-10-09 15:52:03 +020010061/* Hash of mtimes of mailboxes */
10062static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010063/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010064static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010065
Eric Andersencb57d552001-06-28 07:25:16 +000010066/*
Eric Andersenc470f442003-07-28 09:56:35 +000010067 * Print appropriate message(s) if mail has arrived.
10068 * If mail_var_path_changed is set,
10069 * then the value of MAIL has mail_var_path_changed,
10070 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010071 */
Eric Andersenc470f442003-07-28 09:56:35 +000010072static void
10073chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010074{
Eric Andersencb57d552001-06-28 07:25:16 +000010075 const char *mpath;
10076 char *p;
10077 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010078 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010079 struct stackmark smark;
10080 struct stat statb;
10081
Eric Andersencb57d552001-06-28 07:25:16 +000010082 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010083 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010084 new_hash = 0;
10085 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010086 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010087 if (p == NULL)
10088 break;
10089 if (*p == '\0')
10090 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010091 for (q = p; *q; q++)
10092 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010093#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010094 if (q[-1] != '/')
10095 abort();
10096#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010097 q[-1] = '\0'; /* delete trailing '/' */
10098 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010099 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010100 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010101 /* Very simplistic "hash": just a sum of all mtimes */
10102 new_hash += (unsigned)statb.st_mtime;
10103 }
10104 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010105 if (mailtime_hash != 0)
10106 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010107 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010108 }
Eric Andersenc470f442003-07-28 09:56:35 +000010109 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010110 popstackmark(&smark);
10111}
Eric Andersencb57d552001-06-28 07:25:16 +000010112
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010113static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010114changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010115{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010116 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010117}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010118
Denis Vlasenko131ae172007-02-18 13:00:19 +000010119#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010120
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010121
10122/* ============ ??? */
10123
Eric Andersencb57d552001-06-28 07:25:16 +000010124/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010125 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010126 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010127static void
10128setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010129{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010130 char **newparam;
10131 char **ap;
10132 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010133
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010134 for (nparam = 0; argv[nparam]; nparam++)
10135 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010136 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10137 while (*argv) {
10138 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010139 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010140 *ap = NULL;
10141 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010142 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010143 shellparam.nparam = nparam;
10144 shellparam.p = newparam;
10145#if ENABLE_ASH_GETOPTS
10146 shellparam.optind = 1;
10147 shellparam.optoff = -1;
10148#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010149}
10150
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010151/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010152 * Process shell options. The global variable argptr contains a pointer
10153 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010154 *
10155 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10156 * For a non-interactive shell, an error condition encountered
10157 * by a special built-in ... shall cause the shell to write a diagnostic message
10158 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010159 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010160 * ...
10161 * Utility syntax error (option or operand error) Shall exit
10162 * ...
10163 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10164 * we see that bash does not do that (set "finishes" with error code 1 instead,
10165 * and shell continues), and people rely on this behavior!
10166 * Testcase:
10167 * set -o barfoo 2>/dev/null
10168 * echo $?
10169 *
10170 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010171 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010172static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010173plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010174{
10175 int i;
10176
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010177 if (name) {
10178 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010179 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010180 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010181 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010182 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010183 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010184 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010185 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010186 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010187 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010188 if (val) {
10189 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10190 } else {
10191 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10192 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010193 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010194 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010195}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010196static void
10197setoption(int flag, int val)
10198{
10199 int i;
10200
10201 for (i = 0; i < NOPTS; i++) {
10202 if (optletters(i) == flag) {
10203 optlist[i] = val;
10204 return;
10205 }
10206 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010207 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010208 /* NOTREACHED */
10209}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010210static int
Eric Andersenc470f442003-07-28 09:56:35 +000010211options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010212{
10213 char *p;
10214 int val;
10215 int c;
10216
10217 if (cmdline)
10218 minusc = NULL;
10219 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010220 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010221 if (c != '-' && c != '+')
10222 break;
10223 argptr++;
10224 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010225 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010226 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010227 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010228 if (!cmdline) {
10229 /* "-" means turn off -x and -v */
10230 if (p[0] == '\0')
10231 xflag = vflag = 0;
10232 /* "--" means reset params */
10233 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010234 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010235 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010236 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010237 }
Eric Andersencb57d552001-06-28 07:25:16 +000010238 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010239 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010240 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010241 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010242 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010243 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010244 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010245 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010246 /* it already printed err message */
10247 return 1; /* error */
10248 }
Eric Andersencb57d552001-06-28 07:25:16 +000010249 if (*argptr)
10250 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010251 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10252 isloginsh = 1;
10253 /* bash does not accept +-login, we also won't */
10254 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010255 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010256 isloginsh = 1;
10257 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010258 } else {
10259 setoption(c, val);
10260 }
10261 }
10262 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010263 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010264}
10265
Eric Andersencb57d552001-06-28 07:25:16 +000010266/*
Eric Andersencb57d552001-06-28 07:25:16 +000010267 * The shift builtin command.
10268 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010269static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010270shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010271{
10272 int n;
10273 char **ap1, **ap2;
10274
10275 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010276 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010277 n = number(argv[1]);
10278 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010279 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010280 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010281 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010282 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010283 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010284 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010285 }
10286 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010287 while ((*ap2++ = *ap1++) != NULL)
10288 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010289#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010290 shellparam.optind = 1;
10291 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010292#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010293 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010294 return 0;
10295}
10296
Eric Andersencb57d552001-06-28 07:25:16 +000010297/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010298 * POSIX requires that 'set' (but not export or readonly) output the
10299 * variables in lexicographic order - by the locale's collating order (sigh).
10300 * Maybe we could keep them in an ordered balanced binary tree
10301 * instead of hashed lists.
10302 * For now just roll 'em through qsort for printing...
10303 */
10304static int
10305showvars(const char *sep_prefix, int on, int off)
10306{
10307 const char *sep;
10308 char **ep, **epend;
10309
10310 ep = listvars(on, off, &epend);
10311 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10312
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010313 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010314
10315 for (; ep < epend; ep++) {
10316 const char *p;
10317 const char *q;
10318
10319 p = strchrnul(*ep, '=');
10320 q = nullstr;
10321 if (*p)
10322 q = single_quote(++p);
10323 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10324 }
10325 return 0;
10326}
10327
10328/*
Eric Andersencb57d552001-06-28 07:25:16 +000010329 * The set command builtin.
10330 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010331static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010332setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010333{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010334 int retval;
10335
Denis Vlasenko68404f12008-03-17 09:00:54 +000010336 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010337 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010338
Denis Vlasenkob012b102007-02-19 22:43:01 +000010339 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010340 retval = options(/*cmdline:*/ 0);
10341 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010342 optschanged();
10343 if (*argptr != NULL) {
10344 setparam(argptr);
10345 }
Eric Andersencb57d552001-06-28 07:25:16 +000010346 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010347 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010348 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010349}
10350
Denis Vlasenko131ae172007-02-18 13:00:19 +000010351#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010352static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010353change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010354{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010355 uint32_t t;
10356
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010357 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010358 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010359 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010360 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010361 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010362 vrandom.flags &= ~VNOFUNC;
10363 } else {
10364 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010365 t = strtoul(value, NULL, 10);
10366 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010367 }
Eric Andersenef02f822004-03-11 13:34:24 +000010368}
Eric Andersen16767e22004-03-16 05:14:10 +000010369#endif
10370
Denis Vlasenko131ae172007-02-18 13:00:19 +000010371#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010372static int
Eric Andersenc470f442003-07-28 09:56:35 +000010373getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010374{
10375 char *p, *q;
10376 char c = '?';
10377 int done = 0;
10378 int err = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010379 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010380 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010381
Denys Vlasenko9c541002015-10-07 15:44:36 +020010382 sbuf[1] = '\0';
10383
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010384 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010385 return 1;
10386 optnext = optfirst + *param_optind - 1;
10387
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010388 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010389 p = NULL;
10390 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010391 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010392 if (p == NULL || *p == '\0') {
10393 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010394 p = *optnext;
10395 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010396 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010397 p = NULL;
10398 done = 1;
10399 goto out;
10400 }
10401 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010402 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010403 goto atend;
10404 }
10405
10406 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010407 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010408 if (*q == '\0') {
10409 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010410 sbuf[0] = c;
10411 /*sbuf[1] = '\0'; - already is */
10412 err |= setvarsafe("OPTARG", sbuf, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010413 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010414 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010415 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010416 }
10417 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010418 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010419 }
10420 if (*++q == ':')
10421 q++;
10422 }
10423
10424 if (*++q == ':') {
10425 if (*p == '\0' && (p = *optnext) == NULL) {
10426 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010427 sbuf[0] = c;
10428 /*sbuf[1] = '\0'; - already is */
10429 err |= setvarsafe("OPTARG", sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010430 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010431 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010432 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010433 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010434 c = '?';
10435 }
Eric Andersenc470f442003-07-28 09:56:35 +000010436 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010437 }
10438
10439 if (p == *optnext)
10440 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010441 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010442 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010443 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010444 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010445 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010446 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010447 *param_optind = optnext - optfirst + 1;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010448 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC);
10449 sbuf[0] = c;
10450 /*sbuf[1] = '\0'; - already is */
10451 err |= setvarsafe(optvar, sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010452 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010453 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010454 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010455 flush_stdout_stderr();
10456 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010457 }
10458 return done;
10459}
Eric Andersenc470f442003-07-28 09:56:35 +000010460
10461/*
10462 * The getopts builtin. Shellparam.optnext points to the next argument
10463 * to be processed. Shellparam.optptr points to the next character to
10464 * be processed in the current argument. If shellparam.optnext is NULL,
10465 * then it's the first time getopts has been called.
10466 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010467static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010468getoptscmd(int argc, char **argv)
10469{
10470 char **optbase;
10471
10472 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010473 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010474 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010475 optbase = shellparam.p;
10476 if (shellparam.optind > shellparam.nparam + 1) {
10477 shellparam.optind = 1;
10478 shellparam.optoff = -1;
10479 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010480 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010481 optbase = &argv[3];
10482 if (shellparam.optind > argc - 2) {
10483 shellparam.optind = 1;
10484 shellparam.optoff = -1;
10485 }
10486 }
10487
10488 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010489 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010490}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010491#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010492
Eric Andersencb57d552001-06-28 07:25:16 +000010493
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010494/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010495
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010496struct heredoc {
10497 struct heredoc *next; /* next here document in list */
10498 union node *here; /* redirection node */
10499 char *eofmark; /* string indicating end of input */
10500 smallint striptabs; /* if set, strip leading tabs */
10501};
10502
10503static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010504static smallint quoteflag; /* set if (part of) last token was quoted */
10505static token_id_t lasttoken; /* last token read (integer id Txxx) */
10506static struct heredoc *heredoclist; /* list of here documents to read */
10507static char *wordtext; /* text of last word returned by readtoken */
10508static struct nodelist *backquotelist;
10509static union node *redirnode;
10510static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010511
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010512static const char *
10513tokname(char *buf, int tok)
10514{
10515 if (tok < TSEMI)
10516 return tokname_array[tok] + 1;
10517 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10518 return buf;
10519}
10520
10521/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010522 * Called when an unexpected token is read during the parse. The argument
10523 * is the token that is expected, or -1 if more than one type of token can
10524 * occur at this point.
10525 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010526static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010527static void
10528raise_error_unexpected_syntax(int token)
10529{
10530 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010531 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010532 int l;
10533
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010534 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010535 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010536 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010537 raise_error_syntax(msg);
10538 /* NOTREACHED */
10539}
Eric Andersencb57d552001-06-28 07:25:16 +000010540
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010541#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010542
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010543/* parsing is heavily cross-recursive, need these forward decls */
10544static union node *andor(void);
10545static union node *pipeline(void);
10546static union node *parse_command(void);
10547static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010548static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010549static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010550
Eric Andersenc470f442003-07-28 09:56:35 +000010551static union node *
10552list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010553{
10554 union node *n1, *n2, *n3;
10555 int tok;
10556
Eric Andersencb57d552001-06-28 07:25:16 +000010557 n1 = NULL;
10558 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010559 switch (peektoken()) {
10560 case TNL:
10561 if (!(nlflag & 1))
10562 break;
10563 parseheredoc();
10564 return n1;
10565
10566 case TEOF:
10567 if (!n1 && (nlflag & 1))
10568 n1 = NODE_EOF;
10569 parseheredoc();
10570 return n1;
10571 }
10572
10573 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10574 if (nlflag == 2 && tokname_array[peektoken()][0])
10575 return n1;
10576 nlflag |= 2;
10577
Eric Andersencb57d552001-06-28 07:25:16 +000010578 n2 = andor();
10579 tok = readtoken();
10580 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010581 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010582 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010583 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010584 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010585 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010586 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010587 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010588 n2 = n3;
10589 }
10590 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010591 }
10592 }
10593 if (n1 == NULL) {
10594 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010595 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010596 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010597 n3->type = NSEMI;
10598 n3->nbinary.ch1 = n1;
10599 n3->nbinary.ch2 = n2;
10600 n1 = n3;
10601 }
10602 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010603 case TNL:
10604 case TEOF:
10605 tokpushback = 1;
10606 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010607 case TBACKGND:
10608 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010609 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010610 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010611 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010612 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010613 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010614 return n1;
10615 }
10616 }
10617}
10618
Eric Andersenc470f442003-07-28 09:56:35 +000010619static union node *
10620andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010621{
Eric Andersencb57d552001-06-28 07:25:16 +000010622 union node *n1, *n2, *n3;
10623 int t;
10624
Eric Andersencb57d552001-06-28 07:25:16 +000010625 n1 = pipeline();
10626 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010627 t = readtoken();
10628 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010629 t = NAND;
10630 } else if (t == TOR) {
10631 t = NOR;
10632 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010633 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010634 return n1;
10635 }
Eric Andersenc470f442003-07-28 09:56:35 +000010636 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010637 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010638 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010639 n3->type = t;
10640 n3->nbinary.ch1 = n1;
10641 n3->nbinary.ch2 = n2;
10642 n1 = n3;
10643 }
10644}
10645
Eric Andersenc470f442003-07-28 09:56:35 +000010646static union node *
10647pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010648{
Eric Andersencb57d552001-06-28 07:25:16 +000010649 union node *n1, *n2, *pipenode;
10650 struct nodelist *lp, *prev;
10651 int negate;
10652
10653 negate = 0;
10654 TRACE(("pipeline: entered\n"));
10655 if (readtoken() == TNOT) {
10656 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010657 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010658 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010659 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010660 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010661 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010662 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010663 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010664 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010665 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010666 pipenode->npipe.cmdlist = lp;
10667 lp->n = n1;
10668 do {
10669 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010670 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010671 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010672 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010673 prev->next = lp;
10674 } while (readtoken() == TPIPE);
10675 lp->next = NULL;
10676 n1 = pipenode;
10677 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010678 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010679 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010680 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010681 n2->type = NNOT;
10682 n2->nnot.com = n1;
10683 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010684 }
10685 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010686}
10687
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010688static union node *
10689makename(void)
10690{
10691 union node *n;
10692
Denis Vlasenko597906c2008-02-20 16:38:54 +000010693 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010694 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010695 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010696 n->narg.text = wordtext;
10697 n->narg.backquote = backquotelist;
10698 return n;
10699}
10700
10701static void
10702fixredir(union node *n, const char *text, int err)
10703{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010704 int fd;
10705
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010706 TRACE(("Fix redir %s %d\n", text, err));
10707 if (!err)
10708 n->ndup.vname = NULL;
10709
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010710 fd = bb_strtou(text, NULL, 10);
10711 if (!errno && fd >= 0)
10712 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010713 else if (LONE_DASH(text))
10714 n->ndup.dupfd = -1;
10715 else {
10716 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010717 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010718 n->ndup.vname = makename();
10719 }
10720}
10721
10722/*
10723 * Returns true if the text contains nothing to expand (no dollar signs
10724 * or backquotes).
10725 */
10726static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010727noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010728{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010729 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010730
Denys Vlasenkocd716832009-11-28 22:14:02 +010010731 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010732 if (c == CTLQUOTEMARK)
10733 continue;
10734 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010735 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010736 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010737 return 0;
10738 }
10739 return 1;
10740}
10741
10742static void
10743parsefname(void)
10744{
10745 union node *n = redirnode;
10746
10747 if (readtoken() != TWORD)
10748 raise_error_unexpected_syntax(-1);
10749 if (n->type == NHERE) {
10750 struct heredoc *here = heredoc;
10751 struct heredoc *p;
10752 int i;
10753
10754 if (quoteflag == 0)
10755 n->type = NXHERE;
10756 TRACE(("Here document %d\n", n->type));
10757 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010758 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010759 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010760 here->eofmark = wordtext;
10761 here->next = NULL;
10762 if (heredoclist == NULL)
10763 heredoclist = here;
10764 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010765 for (p = heredoclist; p->next; p = p->next)
10766 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010767 p->next = here;
10768 }
10769 } else if (n->type == NTOFD || n->type == NFROMFD) {
10770 fixredir(n, wordtext, 0);
10771 } else {
10772 n->nfile.fname = makename();
10773 }
10774}
Eric Andersencb57d552001-06-28 07:25:16 +000010775
Eric Andersenc470f442003-07-28 09:56:35 +000010776static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010777simplecmd(void)
10778{
10779 union node *args, **app;
10780 union node *n = NULL;
10781 union node *vars, **vpp;
10782 union node **rpp, *redir;
10783 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010784#if ENABLE_ASH_BASH_COMPAT
10785 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000010786 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010787#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010788
10789 args = NULL;
10790 app = &args;
10791 vars = NULL;
10792 vpp = &vars;
10793 redir = NULL;
10794 rpp = &redir;
10795
10796 savecheckkwd = CHKALIAS;
10797 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010798 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010799 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010800 t = readtoken();
10801 switch (t) {
10802#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000010803 case TFUNCTION:
10804 if (peektoken() != TWORD)
10805 raise_error_unexpected_syntax(TWORD);
10806 function_flag = 1;
10807 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010808 case TAND: /* "&&" */
10809 case TOR: /* "||" */
10810 if (!double_brackets_flag) {
10811 tokpushback = 1;
10812 goto out;
10813 }
10814 wordtext = (char *) (t == TAND ? "-a" : "-o");
10815#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010816 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010817 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010818 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010819 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010820 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010821#if ENABLE_ASH_BASH_COMPAT
10822 if (strcmp("[[", wordtext) == 0)
10823 double_brackets_flag = 1;
10824 else if (strcmp("]]", wordtext) == 0)
10825 double_brackets_flag = 0;
10826#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010827 n->narg.backquote = backquotelist;
10828 if (savecheckkwd && isassignment(wordtext)) {
10829 *vpp = n;
10830 vpp = &n->narg.next;
10831 } else {
10832 *app = n;
10833 app = &n->narg.next;
10834 savecheckkwd = 0;
10835 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000010836#if ENABLE_ASH_BASH_COMPAT
10837 if (function_flag) {
10838 checkkwd = CHKNL | CHKKWD;
10839 switch (peektoken()) {
10840 case TBEGIN:
10841 case TIF:
10842 case TCASE:
10843 case TUNTIL:
10844 case TWHILE:
10845 case TFOR:
10846 goto do_func;
10847 case TLP:
10848 function_flag = 0;
10849 break;
10850 case TWORD:
10851 if (strcmp("[[", wordtext) == 0)
10852 goto do_func;
10853 /* fall through */
10854 default:
10855 raise_error_unexpected_syntax(-1);
10856 }
10857 }
10858#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010859 break;
10860 case TREDIR:
10861 *rpp = n = redirnode;
10862 rpp = &n->nfile.next;
10863 parsefname(); /* read name of redirection file */
10864 break;
10865 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000010866 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010867 if (args && app == &args->narg.next
10868 && !vars && !redir
10869 ) {
10870 struct builtincmd *bcmd;
10871 const char *name;
10872
10873 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000010874 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010875 raise_error_unexpected_syntax(TRP);
10876 name = n->narg.text;
10877 if (!goodname(name)
10878 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10879 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010880 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010881 }
10882 n->type = NDEFUN;
10883 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10884 n->narg.next = parse_command();
10885 return n;
10886 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000010887 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010888 /* fall through */
10889 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010890 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010891 goto out;
10892 }
10893 }
10894 out:
10895 *app = NULL;
10896 *vpp = NULL;
10897 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010898 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010899 n->type = NCMD;
10900 n->ncmd.args = args;
10901 n->ncmd.assign = vars;
10902 n->ncmd.redirect = redir;
10903 return n;
10904}
10905
10906static union node *
10907parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010908{
Eric Andersencb57d552001-06-28 07:25:16 +000010909 union node *n1, *n2;
10910 union node *ap, **app;
10911 union node *cp, **cpp;
10912 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000010913 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000010914 int t;
10915
10916 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000010917 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000010918
Eric Andersencb57d552001-06-28 07:25:16 +000010919 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000010920 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010921 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000010922 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000010923 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010924 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010925 n1->type = NIF;
10926 n1->nif.test = list(0);
10927 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010928 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010929 n1->nif.ifpart = list(0);
10930 n2 = n1;
10931 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010932 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010933 n2 = n2->nif.elsepart;
10934 n2->type = NIF;
10935 n2->nif.test = list(0);
10936 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010937 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010938 n2->nif.ifpart = list(0);
10939 }
10940 if (lasttoken == TELSE)
10941 n2->nif.elsepart = list(0);
10942 else {
10943 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010944 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010945 }
Eric Andersenc470f442003-07-28 09:56:35 +000010946 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000010947 break;
10948 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010949 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000010950 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010951 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010952 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000010953 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010954 got = readtoken();
10955 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010956 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000010957 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010958 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010959 }
10960 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010961 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010962 break;
10963 }
10964 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010965 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000010966 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010967 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000010968 n1->type = NFOR;
10969 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010010970 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010971 if (readtoken() == TIN) {
10972 app = &ap;
10973 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010974 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010975 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010976 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010977 n2->narg.text = wordtext;
10978 n2->narg.backquote = backquotelist;
10979 *app = n2;
10980 app = &n2->narg.next;
10981 }
10982 *app = NULL;
10983 n1->nfor.args = ap;
10984 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010985 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000010986 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010987 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010988 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010989 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010990 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010991 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000010992 n1->nfor.args = n2;
10993 /*
10994 * Newline or semicolon here is optional (but note
10995 * that the original Bourne shell only allowed NL).
10996 */
Ron Yorstonab80e012015-08-03 13:46:00 +010010997 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010998 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010999 }
Eric Andersenc470f442003-07-28 09:56:35 +000011000 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011001 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011002 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011003 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011004 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011005 break;
11006 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011007 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011008 n1->type = NCASE;
11009 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011010 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011011 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011012 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011013 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011014 n2->narg.text = wordtext;
11015 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011016 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11017 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011018 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011019 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011020 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011021 checkkwd = CHKNL | CHKKWD;
11022 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011023 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011024 if (lasttoken == TLP)
11025 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011026 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011027 cp->type = NCLIST;
11028 app = &cp->nclist.pattern;
11029 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011030 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011031 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011032 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011033 ap->narg.text = wordtext;
11034 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011035 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011036 break;
11037 app = &ap->narg.next;
11038 readtoken();
11039 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011040 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011041 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011042 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011043 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011044
Eric Andersenc470f442003-07-28 09:56:35 +000011045 cpp = &cp->nclist.next;
11046
11047 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011048 t = readtoken();
11049 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011050 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011051 raise_error_unexpected_syntax(TENDCASE);
11052 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011053 }
Eric Andersenc470f442003-07-28 09:56:35 +000011054 }
Eric Andersencb57d552001-06-28 07:25:16 +000011055 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011056 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011057 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011058 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011059 n1->type = NSUBSHELL;
11060 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011061 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011062 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011063 break;
11064 case TBEGIN:
11065 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011066 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011067 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011068 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011069 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011070 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011071 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011072 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011073 }
11074
Eric Andersenc470f442003-07-28 09:56:35 +000011075 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011076 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011077
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011078 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011079 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011080 checkkwd = CHKKWD | CHKALIAS;
11081 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011082 while (readtoken() == TREDIR) {
11083 *rpp = n2 = redirnode;
11084 rpp = &n2->nfile.next;
11085 parsefname();
11086 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011087 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011088 *rpp = NULL;
11089 if (redir) {
11090 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011091 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011092 n2->type = NREDIR;
11093 n2->nredir.n = n1;
11094 n1 = n2;
11095 }
11096 n1->nredir.redirect = redir;
11097 }
Eric Andersencb57d552001-06-28 07:25:16 +000011098 return n1;
11099}
11100
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011101#if ENABLE_ASH_BASH_COMPAT
11102static int decode_dollar_squote(void)
11103{
11104 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11105 int c, cnt;
11106 char *p;
11107 char buf[4];
11108
11109 c = pgetc();
11110 p = strchr(C_escapes, c);
11111 if (p) {
11112 buf[0] = c;
11113 p = buf;
11114 cnt = 3;
11115 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11116 do {
11117 c = pgetc();
11118 *++p = c;
11119 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11120 pungetc();
11121 } else if (c == 'x') { /* \xHH */
11122 do {
11123 c = pgetc();
11124 *++p = c;
11125 } while (isxdigit(c) && --cnt);
11126 pungetc();
11127 if (cnt == 3) { /* \x but next char is "bad" */
11128 c = 'x';
11129 goto unrecognized;
11130 }
11131 } else { /* simple seq like \\ or \t */
11132 p++;
11133 }
11134 *p = '\0';
11135 p = buf;
11136 c = bb_process_escape_sequence((void*)&p);
11137 } else { /* unrecognized "\z": print both chars unless ' or " */
11138 if (c != '\'' && c != '"') {
11139 unrecognized:
11140 c |= 0x100; /* "please encode \, then me" */
11141 }
11142 }
11143 return c;
11144}
11145#endif
11146
Eric Andersencb57d552001-06-28 07:25:16 +000011147/*
11148 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11149 * is not NULL, read a here document. In the latter case, eofmark is the
11150 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011151 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011152 * is the first character of the input token or document.
11153 *
11154 * Because C does not have internal subroutines, I have simulated them
11155 * using goto's to implement the subroutine linkage. The following macros
11156 * will run code that appears at the end of readtoken1.
11157 */
Eric Andersen2870d962001-07-02 17:27:21 +000011158#define CHECKEND() {goto checkend; checkend_return:;}
11159#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11160#define PARSESUB() {goto parsesub; parsesub_return:;}
11161#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11162#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11163#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011164static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011165readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011166{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011167 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011168 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011169 char *out;
11170 int len;
11171 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011172 struct nodelist *bqlist;
11173 smallint quotef;
11174 smallint dblquote;
11175 smallint oldstyle;
11176 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011177#if ENABLE_ASH_EXPAND_PRMT
11178 smallint pssyntax; /* we are expanding a prompt string */
11179#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011180 int varnest; /* levels of variables expansion */
11181 int arinest; /* levels of arithmetic expansion */
11182 int parenlevel; /* levels of parens in arithmetic */
11183 int dqvarnest; /* levels of variables expansion within double quotes */
11184
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011185 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011186
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011187 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011188 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011189 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011190 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011191#if ENABLE_ASH_EXPAND_PRMT
11192 pssyntax = (syntax == PSSYNTAX);
11193 if (pssyntax)
11194 syntax = DQSYNTAX;
11195#endif
11196 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011197 varnest = 0;
11198 arinest = 0;
11199 parenlevel = 0;
11200 dqvarnest = 0;
11201
11202 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011203 loop:
11204 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011205 CHECKEND(); /* set c to PEOF if at end of here document */
11206 for (;;) { /* until end of line or end of word */
11207 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11208 switch (SIT(c, syntax)) {
11209 case CNL: /* '\n' */
11210 if (syntax == BASESYNTAX)
11211 goto endword; /* exit outer loop */
11212 USTPUTC(c, out);
11213 g_parsefile->linno++;
11214 setprompt_if(doprompt, 2);
11215 c = pgetc();
11216 goto loop; /* continue outer loop */
11217 case CWORD:
11218 USTPUTC(c, out);
11219 break;
11220 case CCTL:
11221 if (eofmark == NULL || dblquote)
11222 USTPUTC(CTLESC, out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011223#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011224 if (c == '\\' && bash_dollar_squote) {
11225 c = decode_dollar_squote();
11226 if (c & 0x100) {
11227 USTPUTC('\\', out);
11228 c = (unsigned char)c;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011229 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011230 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011231#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011232 USTPUTC(c, out);
11233 break;
11234 case CBACK: /* backslash */
11235 c = pgetc_without_PEOA();
11236 if (c == PEOF) {
11237 USTPUTC(CTLESC, out);
11238 USTPUTC('\\', out);
11239 pungetc();
11240 } else if (c == '\n') {
11241 setprompt_if(doprompt, 2);
11242 } else {
11243#if ENABLE_ASH_EXPAND_PRMT
11244 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011245 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011246 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011247 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011248#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011249 /* Backslash is retained if we are in "str" and next char isn't special */
11250 if (dblquote
11251 && c != '\\'
11252 && c != '`'
11253 && c != '$'
11254 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011255 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011256 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011257 }
Ron Yorston549deab2015-05-18 09:57:51 +020011258 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011259 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011260 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011261 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011262 break;
11263 case CSQUOTE:
11264 syntax = SQSYNTAX;
11265 quotemark:
11266 if (eofmark == NULL) {
11267 USTPUTC(CTLQUOTEMARK, out);
11268 }
11269 break;
11270 case CDQUOTE:
11271 syntax = DQSYNTAX;
11272 dblquote = 1;
11273 goto quotemark;
11274 case CENDQUOTE:
11275 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011276 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011277 USTPUTC(c, out);
11278 } else {
11279 if (dqvarnest == 0) {
11280 syntax = BASESYNTAX;
11281 dblquote = 0;
11282 }
11283 quotef = 1;
11284 goto quotemark;
11285 }
11286 break;
11287 case CVAR: /* '$' */
11288 PARSESUB(); /* parse substitution */
11289 break;
11290 case CENDVAR: /* '}' */
11291 if (varnest > 0) {
11292 varnest--;
11293 if (dqvarnest > 0) {
11294 dqvarnest--;
11295 }
11296 c = CTLENDVAR;
11297 }
11298 USTPUTC(c, out);
11299 break;
11300#if ENABLE_SH_MATH_SUPPORT
11301 case CLP: /* '(' in arithmetic */
11302 parenlevel++;
11303 USTPUTC(c, out);
11304 break;
11305 case CRP: /* ')' in arithmetic */
11306 if (parenlevel > 0) {
11307 parenlevel--;
11308 } else {
11309 if (pgetc() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011310 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011311 if (--arinest == 0) {
11312 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011313 }
11314 } else {
11315 /*
11316 * unbalanced parens
11317 * (don't 2nd guess - no error)
11318 */
11319 pungetc();
11320 }
11321 }
11322 USTPUTC(c, out);
11323 break;
11324#endif
11325 case CBQUOTE: /* '`' */
11326 PARSEBACKQOLD();
11327 break;
11328 case CENDFILE:
11329 goto endword; /* exit outer loop */
11330 case CIGN:
11331 break;
11332 default:
11333 if (varnest == 0) {
11334#if ENABLE_ASH_BASH_COMPAT
11335 if (c == '&') {
11336 if (pgetc() == '>')
11337 c = 0x100 + '>'; /* flag &> */
11338 pungetc();
11339 }
11340#endif
11341 goto endword; /* exit outer loop */
11342 }
11343 IF_ASH_ALIAS(if (c != PEOA))
11344 USTPUTC(c, out);
11345 }
11346 c = pgetc_fast();
11347 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011348 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011349
Mike Frysinger98c52642009-04-02 10:02:37 +000011350#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011351 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011352 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011353#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011354 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011355 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011356 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011357 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011358 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011359 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011360 }
11361 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011362 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011363 out = stackblock();
11364 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011365 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011366 && quotef == 0
11367 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011368 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011369 PARSEREDIR(); /* passed as params: out, c */
11370 lasttoken = TREDIR;
11371 return lasttoken;
11372 }
11373 /* else: non-number X seen, interpret it
11374 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011375 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011376 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011377 }
11378 quoteflag = quotef;
11379 backquotelist = bqlist;
11380 grabstackblock(len);
11381 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011382 lasttoken = TWORD;
11383 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011384/* end of readtoken routine */
11385
Eric Andersencb57d552001-06-28 07:25:16 +000011386/*
11387 * Check to see whether we are at the end of the here document. When this
11388 * is called, c is set to the first character of the next input line. If
11389 * we are at the end of the here document, this routine sets the c to PEOF.
11390 */
Eric Andersenc470f442003-07-28 09:56:35 +000011391checkend: {
11392 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011393#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011394 if (c == PEOA)
11395 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011396#endif
11397 if (striptabs) {
11398 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011399 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011400 }
Eric Andersenc470f442003-07-28 09:56:35 +000011401 }
11402 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011403 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011404 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011405
Eric Andersenc470f442003-07-28 09:56:35 +000011406 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011407 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11408 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011409 if (*p == '\n' && *q == '\0') {
11410 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011411 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011412 needprompt = doprompt;
11413 } else {
11414 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011415 }
11416 }
11417 }
11418 }
Eric Andersenc470f442003-07-28 09:56:35 +000011419 goto checkend_return;
11420}
Eric Andersencb57d552001-06-28 07:25:16 +000011421
Eric Andersencb57d552001-06-28 07:25:16 +000011422/*
11423 * Parse a redirection operator. The variable "out" points to a string
11424 * specifying the fd to be redirected. The variable "c" contains the
11425 * first character of the redirection operator.
11426 */
Eric Andersenc470f442003-07-28 09:56:35 +000011427parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011428 /* out is already checked to be a valid number or "" */
11429 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011430 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011431
Denis Vlasenko597906c2008-02-20 16:38:54 +000011432 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011433 if (c == '>') {
11434 np->nfile.fd = 1;
11435 c = pgetc();
11436 if (c == '>')
11437 np->type = NAPPEND;
11438 else if (c == '|')
11439 np->type = NCLOBBER;
11440 else if (c == '&')
11441 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011442 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011443 else {
11444 np->type = NTO;
11445 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011446 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011447 }
11448#if ENABLE_ASH_BASH_COMPAT
11449 else if (c == 0x100 + '>') { /* this flags &> redirection */
11450 np->nfile.fd = 1;
11451 pgetc(); /* this is '>', no need to check */
11452 np->type = NTO2;
11453 }
11454#endif
11455 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011456 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011457 c = pgetc();
11458 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011459 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011460 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011461 np = stzalloc(sizeof(struct nhere));
11462 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011463 }
11464 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011465 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011466 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011467 c = pgetc();
11468 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011469 heredoc->striptabs = 1;
11470 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011471 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011472 pungetc();
11473 }
11474 break;
11475
11476 case '&':
11477 np->type = NFROMFD;
11478 break;
11479
11480 case '>':
11481 np->type = NFROMTO;
11482 break;
11483
11484 default:
11485 np->type = NFROM;
11486 pungetc();
11487 break;
11488 }
Eric Andersencb57d552001-06-28 07:25:16 +000011489 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011490 if (fd >= 0)
11491 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011492 redirnode = np;
11493 goto parseredir_return;
11494}
Eric Andersencb57d552001-06-28 07:25:16 +000011495
Eric Andersencb57d552001-06-28 07:25:16 +000011496/*
11497 * Parse a substitution. At this point, we have read the dollar sign
11498 * and nothing else.
11499 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011500
11501/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11502 * (assuming ascii char codes, as the original implementation did) */
11503#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011504 (((unsigned)(c) - 33 < 32) \
11505 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011506parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011507 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011508 int typeloc;
11509 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011510
Eric Andersenc470f442003-07-28 09:56:35 +000011511 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011512 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011513 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011514 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011515#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011516 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011517 bash_dollar_squote = 1;
11518 else
11519#endif
11520 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011521 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011522 } else if (c == '(') {
11523 /* $(command) or $((arith)) */
Eric Andersenc470f442003-07-28 09:56:35 +000011524 if (pgetc() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011525#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011526 PARSEARITH();
11527#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011528 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011529#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011530 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011531 pungetc();
11532 PARSEBACKQNEW();
11533 }
11534 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011535 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011536 USTPUTC(CTLVAR, out);
11537 typeloc = out - (char *)stackblock();
11538 USTPUTC(VSNORMAL, out);
11539 subtype = VSNORMAL;
11540 if (c == '{') {
11541 c = pgetc();
11542 if (c == '#') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011543 c = pgetc();
11544 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011545 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011546 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011547 subtype = VSLENGTH; /* ${#VAR} */
11548 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011549 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011550 }
Eric Andersenc470f442003-07-28 09:56:35 +000011551 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011552 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011553 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011554 do {
11555 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011556 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011557 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011558 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011559 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011560 do {
11561 STPUTC(c, out);
11562 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011563 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011564 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011565 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011566 USTPUTC(c, out);
11567 c = pgetc();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011568 } else {
11569 badsub:
11570 raise_error_syntax("bad substitution");
11571 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011572 if (c != '}' && subtype == VSLENGTH) {
11573 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011574 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011575 }
Eric Andersencb57d552001-06-28 07:25:16 +000011576
Eric Andersenc470f442003-07-28 09:56:35 +000011577 STPUTC('=', out);
11578 flags = 0;
11579 if (subtype == 0) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011580 /* ${VAR...} but not $VAR or ${#VAR} */
11581 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011582 switch (c) {
11583 case ':':
Eric Andersenc470f442003-07-28 09:56:35 +000011584 c = pgetc();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011585#if ENABLE_ASH_BASH_COMPAT
11586 if (c == ':' || c == '$' || isdigit(c)) {
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011587//TODO: support more general format ${v:EXPR:EXPR},
11588// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011589 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011590 pungetc();
11591 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011592 }
11593#endif
11594 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011595 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011596 default: {
11597 static const char types[] ALIGN1 = "}-+?=";
11598 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011599 if (p == NULL)
11600 goto badsub;
11601 subtype = p - types + VSNORMAL;
11602 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011603 }
Eric Andersenc470f442003-07-28 09:56:35 +000011604 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011605 case '#': {
11606 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011607 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011608 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011609 if (c != cc)
11610 goto do_pungetc;
11611 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011612 break;
11613 }
11614#if ENABLE_ASH_BASH_COMPAT
11615 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011616 /* ${v/[/]pattern/repl} */
11617//TODO: encode pattern and repl separately.
11618// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011619 subtype = VSREPLACE;
11620 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011621 if (c != '/')
11622 goto do_pungetc;
11623 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011624 break;
11625#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011626 }
Eric Andersenc470f442003-07-28 09:56:35 +000011627 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011628 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011629 pungetc();
11630 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011631 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011632 if (subtype != VSNORMAL) {
11633 varnest++;
Ron Yorston7e4ed262015-05-18 09:54:43 +020011634 if (dblquote) {
Eric Andersenc470f442003-07-28 09:56:35 +000011635 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011636 }
11637 }
11638 }
Eric Andersenc470f442003-07-28 09:56:35 +000011639 goto parsesub_return;
11640}
Eric Andersencb57d552001-06-28 07:25:16 +000011641
Eric Andersencb57d552001-06-28 07:25:16 +000011642/*
11643 * Called to parse command substitutions. Newstyle is set if the command
11644 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11645 * list of commands (passed by reference), and savelen is the number of
11646 * characters on the top of the stack which must be preserved.
11647 */
Eric Andersenc470f442003-07-28 09:56:35 +000011648parsebackq: {
11649 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011650 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011651 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011652 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011653 smallint saveprompt = 0;
11654
Eric Andersenc470f442003-07-28 09:56:35 +000011655 str = NULL;
11656 savelen = out - (char *)stackblock();
11657 if (savelen > 0) {
Ron Yorston072fc602015-07-01 16:46:18 +010011658 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011659 memcpy(str, stackblock(), savelen);
11660 }
Eric Andersenc470f442003-07-28 09:56:35 +000011661 if (oldstyle) {
11662 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011663 * treatment to some slashes, and then push the string and
11664 * reread it as input, interpreting it normally.
11665 */
Eric Andersenc470f442003-07-28 09:56:35 +000011666 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011667 size_t psavelen;
11668 char *pstr;
11669
Eric Andersenc470f442003-07-28 09:56:35 +000011670 STARTSTACKSTR(pout);
11671 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011672 int pc;
11673
11674 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011675 pc = pgetc();
11676 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011677 case '`':
11678 goto done;
11679
11680 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011681 pc = pgetc();
11682 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011683 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011684 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011685 /*
11686 * If eating a newline, avoid putting
11687 * the newline into the new character
11688 * stream (via the STPUTC after the
11689 * switch).
11690 */
11691 continue;
11692 }
11693 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011694 && (!dblquote || pc != '"')
11695 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011696 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011697 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011698 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011699 break;
11700 }
11701 /* fall through */
11702
11703 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011704 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011705 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011706 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011707
11708 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011709 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011710 needprompt = doprompt;
11711 break;
11712
11713 default:
11714 break;
11715 }
11716 STPUTC(pc, pout);
11717 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011718 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011719 STPUTC('\0', pout);
11720 psavelen = pout - (char *)stackblock();
11721 if (psavelen > 0) {
11722 pstr = grabstackstr(pout);
11723 setinputstring(pstr);
11724 }
11725 }
11726 nlpp = &bqlist;
11727 while (*nlpp)
11728 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011729 *nlpp = stzalloc(sizeof(**nlpp));
11730 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011731
11732 if (oldstyle) {
11733 saveprompt = doprompt;
11734 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011735 }
11736
Eric Andersenc470f442003-07-28 09:56:35 +000011737 n = list(2);
11738
11739 if (oldstyle)
11740 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011741 else if (readtoken() != TRP)
11742 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011743
11744 (*nlpp)->n = n;
11745 if (oldstyle) {
11746 /*
11747 * Start reading from old file again, ignoring any pushed back
11748 * tokens left from the backquote parsing
11749 */
11750 popfile();
11751 tokpushback = 0;
11752 }
11753 while (stackblocksize() <= savelen)
11754 growstackblock();
11755 STARTSTACKSTR(out);
11756 if (str) {
11757 memcpy(out, str, savelen);
11758 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011759 }
Ron Yorston549deab2015-05-18 09:57:51 +020011760 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011761 if (oldstyle)
11762 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011763 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011764}
11765
Mike Frysinger98c52642009-04-02 10:02:37 +000011766#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011767/*
11768 * Parse an arithmetic expansion (indicate start of one and set state)
11769 */
Eric Andersenc470f442003-07-28 09:56:35 +000011770parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011771 if (++arinest == 1) {
11772 prevsyntax = syntax;
11773 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011774 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011775 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011776 goto parsearith_return;
11777}
11778#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011779} /* end of readtoken */
11780
Eric Andersencb57d552001-06-28 07:25:16 +000011781/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011782 * Read the next input token.
11783 * If the token is a word, we set backquotelist to the list of cmds in
11784 * backquotes. We set quoteflag to true if any part of the word was
11785 * quoted.
11786 * If the token is TREDIR, then we set redirnode to a structure containing
11787 * the redirection.
11788 * In all cases, the variable startlinno is set to the number of the line
11789 * on which the token starts.
11790 *
11791 * [Change comment: here documents and internal procedures]
11792 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11793 * word parsing code into a separate routine. In this case, readtoken
11794 * doesn't need to have any internal procedures, but parseword does.
11795 * We could also make parseoperator in essence the main routine, and
11796 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011797 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011798#define NEW_xxreadtoken
11799#ifdef NEW_xxreadtoken
11800/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011801static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011802 '\n', '(', ')', /* singles */
11803 '&', '|', ';', /* doubles */
11804 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011805};
Eric Andersencb57d552001-06-28 07:25:16 +000011806
Denis Vlasenko834dee72008-10-07 09:18:30 +000011807#define xxreadtoken_singles 3
11808#define xxreadtoken_doubles 3
11809
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011810static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011811 TNL, TLP, TRP, /* only single occurrence allowed */
11812 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11813 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011814 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011815};
11816
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011817static int
11818xxreadtoken(void)
11819{
11820 int c;
11821
11822 if (tokpushback) {
11823 tokpushback = 0;
11824 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011825 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011826 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011827 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011828 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011829 c = pgetc_fast();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011830 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011831 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011832
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011833 if (c == '#') {
11834 while ((c = pgetc()) != '\n' && c != PEOF)
11835 continue;
11836 pungetc();
11837 } else if (c == '\\') {
11838 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011839 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011840 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011841 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011842 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011843 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011844 } else {
11845 const char *p;
11846
11847 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11848 if (c != PEOF) {
11849 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011850 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011851 needprompt = doprompt;
11852 }
11853
11854 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011855 if (p == NULL)
11856 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011857
Denis Vlasenko834dee72008-10-07 09:18:30 +000011858 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11859 int cc = pgetc();
11860 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011861 p += xxreadtoken_doubles + 1;
11862 } else {
11863 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011864#if ENABLE_ASH_BASH_COMPAT
11865 if (c == '&' && cc == '>') /* &> */
11866 break; /* return readtoken1(...) */
11867#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011868 }
11869 }
11870 }
11871 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11872 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011873 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011874 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011875
11876 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011877}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011878#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011879#define RETURN(token) return lasttoken = token
11880static int
11881xxreadtoken(void)
11882{
11883 int c;
11884
11885 if (tokpushback) {
11886 tokpushback = 0;
11887 return lasttoken;
11888 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011889 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011890 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011891 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011892 c = pgetc_fast();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011893 switch (c) {
11894 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011895 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011896 continue;
11897 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011898 while ((c = pgetc()) != '\n' && c != PEOF)
11899 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011900 pungetc();
11901 continue;
11902 case '\\':
11903 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011904 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011905 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011906 continue;
11907 }
11908 pungetc();
11909 goto breakloop;
11910 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011911 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011912 needprompt = doprompt;
11913 RETURN(TNL);
11914 case PEOF:
11915 RETURN(TEOF);
11916 case '&':
11917 if (pgetc() == '&')
11918 RETURN(TAND);
11919 pungetc();
11920 RETURN(TBACKGND);
11921 case '|':
11922 if (pgetc() == '|')
11923 RETURN(TOR);
11924 pungetc();
11925 RETURN(TPIPE);
11926 case ';':
11927 if (pgetc() == ';')
11928 RETURN(TENDCASE);
11929 pungetc();
11930 RETURN(TSEMI);
11931 case '(':
11932 RETURN(TLP);
11933 case ')':
11934 RETURN(TRP);
11935 default:
11936 goto breakloop;
11937 }
11938 }
11939 breakloop:
11940 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11941#undef RETURN
11942}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011943#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011944
11945static int
11946readtoken(void)
11947{
11948 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000011949 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011950#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011951 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011952#endif
11953
11954#if ENABLE_ASH_ALIAS
11955 top:
11956#endif
11957
11958 t = xxreadtoken();
11959
11960 /*
11961 * eat newlines
11962 */
Ron Yorston713f07d2015-10-29 16:44:56 +000011963 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011964 while (t == TNL) {
11965 parseheredoc();
11966 t = xxreadtoken();
11967 }
11968 }
11969
11970 if (t != TWORD || quoteflag) {
11971 goto out;
11972 }
11973
11974 /*
11975 * check for keywords
11976 */
Ron Yorston713f07d2015-10-29 16:44:56 +000011977 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011978 const char *const *pp;
11979
11980 pp = findkwd(wordtext);
11981 if (pp) {
11982 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011983 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011984 goto out;
11985 }
11986 }
11987
11988 if (checkkwd & CHKALIAS) {
11989#if ENABLE_ASH_ALIAS
11990 struct alias *ap;
11991 ap = lookupalias(wordtext, 1);
11992 if (ap != NULL) {
11993 if (*ap->val) {
11994 pushstring(ap->val, ap);
11995 }
11996 goto top;
11997 }
11998#endif
11999 }
12000 out:
12001 checkkwd = 0;
12002#if DEBUG
12003 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012004 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012005 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012006 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012007#endif
12008 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012009}
12010
Ron Yorstonc0e00762015-10-29 11:30:55 +000012011static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012012peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012013{
12014 int t;
12015
12016 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012017 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012018 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012019}
Eric Andersencb57d552001-06-28 07:25:16 +000012020
12021/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012022 * Read and parse a command. Returns NODE_EOF on end of file.
12023 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012024 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012025static union node *
12026parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012027{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012028 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012029 checkkwd = 0;
12030 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012031 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012032 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012033 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012034 return list(1);
12035}
12036
12037/*
12038 * Input any here documents.
12039 */
12040static void
12041parseheredoc(void)
12042{
12043 struct heredoc *here;
12044 union node *n;
12045
12046 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012047 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012048
12049 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012050 setprompt_if(needprompt, 2);
12051 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012052 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012053 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012054 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012055 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012056 n->narg.text = wordtext;
12057 n->narg.backquote = backquotelist;
12058 here->here->nhere.doc = n;
12059 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012060 }
Eric Andersencb57d552001-06-28 07:25:16 +000012061}
12062
12063
12064/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012065 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012066 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012067#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012068static const char *
12069expandstr(const char *ps)
12070{
12071 union node n;
12072
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012073 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12074 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012075 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012076 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012077 popfile();
12078
12079 n.narg.type = NARG;
12080 n.narg.next = NULL;
12081 n.narg.text = wordtext;
12082 n.narg.backquote = backquotelist;
12083
Ron Yorston549deab2015-05-18 09:57:51 +020012084 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012085 return stackblock();
12086}
12087#endif
12088
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012089/*
12090 * Execute a command or commands contained in a string.
12091 */
12092static int
12093evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012094{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012095 union node *n;
12096 struct stackmark smark;
12097 int skip;
12098
12099 setinputstring(s);
12100 setstackmark(&smark);
12101
12102 skip = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012103 while ((n = parsecmd(0)) != NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012104 evaltree(n, 0);
12105 popstackmark(&smark);
12106 skip = evalskip;
12107 if (skip)
12108 break;
12109 }
12110 popfile();
12111
12112 skip &= mask;
12113 evalskip = skip;
12114 return skip;
Eric Andersenc470f442003-07-28 09:56:35 +000012115}
12116
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012117/*
12118 * The eval command.
12119 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012120static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012121evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012122{
12123 char *p;
12124 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012125
Denis Vlasenko68404f12008-03-17 09:00:54 +000012126 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012127 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012128 argv += 2;
12129 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012130 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012131 for (;;) {
12132 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012133 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012134 if (p == NULL)
12135 break;
12136 STPUTC(' ', concat);
12137 }
12138 STPUTC('\0', concat);
12139 p = grabstackstr(concat);
12140 }
12141 evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012142 }
12143 return exitstatus;
12144}
12145
12146/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012147 * Read and execute commands.
12148 * "Top" is nonzero for the top level command loop;
12149 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012150 */
12151static int
12152cmdloop(int top)
12153{
12154 union node *n;
12155 struct stackmark smark;
12156 int inter;
12157 int numeof = 0;
12158
12159 TRACE(("cmdloop(%d) called\n", top));
12160 for (;;) {
12161 int skip;
12162
12163 setstackmark(&smark);
12164#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012165 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012166 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012167#endif
12168 inter = 0;
12169 if (iflag && top) {
12170 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012171 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012172 }
12173 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012174#if DEBUG
12175 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012176 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012177#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012178 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012179 if (!top || numeof >= 50)
12180 break;
12181 if (!stoppedjobs()) {
12182 if (!Iflag)
12183 break;
12184 out2str("\nUse \"exit\" to leave shell.\n");
12185 }
12186 numeof++;
12187 } else if (nflag == 0) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012188 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12189 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012190 numeof = 0;
12191 evaltree(n, 0);
12192 }
12193 popstackmark(&smark);
12194 skip = evalskip;
12195
12196 if (skip) {
12197 evalskip = 0;
12198 return skip & SKIPEVAL;
12199 }
12200 }
12201 return 0;
12202}
12203
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012204/*
12205 * Take commands from a file. To be compatible we should do a path
12206 * search for the file, which is necessary to find sub-commands.
12207 */
12208static char *
12209find_dot_file(char *name)
12210{
12211 char *fullname;
12212 const char *path = pathval();
12213 struct stat statb;
12214
12215 /* don't try this for absolute or relative paths */
12216 if (strchr(name, '/'))
12217 return name;
12218
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012219 /* IIRC standards do not say whether . is to be searched.
12220 * And it is even smaller this way, making it unconditional for now:
12221 */
12222 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12223 fullname = name;
12224 goto try_cur_dir;
12225 }
12226
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012227 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012228 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012229 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12230 /*
12231 * Don't bother freeing here, since it will
12232 * be freed by the caller.
12233 */
12234 return fullname;
12235 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012236 if (fullname != name)
12237 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012238 }
12239
12240 /* not found in the PATH */
12241 ash_msg_and_raise_error("%s: not found", name);
12242 /* NOTREACHED */
12243}
12244
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012245static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012246dotcmd(int argc, char **argv)
12247{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012248 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012249 struct strlist *sp;
12250 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012251
12252 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012253 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012254
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012255 if (!argv[1]) {
12256 /* bash says: "bash: .: filename argument required" */
12257 return 2; /* bash compat */
12258 }
12259
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012260 /* "false; . empty_file; echo $?" should print 0, not 1: */
12261 exitstatus = 0;
12262
Denys Vlasenko091f8312013-03-17 14:25:22 +010012263 /* This aborts if file isn't found, which is POSIXly correct.
12264 * bash returns exitcode 1 instead.
12265 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012266 fullname = find_dot_file(argv[1]);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012267 argv += 2;
12268 argc -= 2;
12269 if (argc) { /* argc > 0, argv[0] != NULL */
12270 saveparam = shellparam;
12271 shellparam.malloced = 0;
12272 shellparam.nparam = argc;
12273 shellparam.p = argv;
12274 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012275
Denys Vlasenko091f8312013-03-17 14:25:22 +010012276 /* This aborts if file can't be opened, which is POSIXly correct.
12277 * bash returns exitcode 1 instead.
12278 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012279 setinputfile(fullname, INPUT_PUSH_FILE);
12280 commandname = fullname;
12281 cmdloop(0);
12282 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012283
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012284 if (argc) {
12285 freeparam(&shellparam);
12286 shellparam = saveparam;
12287 };
12288
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012289 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012290}
12291
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012292static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012293exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012294{
12295 if (stoppedjobs())
12296 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012297 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012298 exitstatus = number(argv[1]);
12299 raise_exception(EXEXIT);
12300 /* NOTREACHED */
12301}
12302
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012303/*
12304 * Read a file containing shell functions.
12305 */
12306static void
12307readcmdfile(char *name)
12308{
12309 setinputfile(name, INPUT_PUSH_FILE);
12310 cmdloop(0);
12311 popfile();
12312}
12313
12314
Denis Vlasenkocc571512007-02-23 21:10:35 +000012315/* ============ find_command inplementation */
12316
12317/*
12318 * Resolve a command name. If you change this routine, you may have to
12319 * change the shellexec routine as well.
12320 */
12321static void
12322find_command(char *name, struct cmdentry *entry, int act, const char *path)
12323{
12324 struct tblentry *cmdp;
12325 int idx;
12326 int prev;
12327 char *fullname;
12328 struct stat statb;
12329 int e;
12330 int updatetbl;
12331 struct builtincmd *bcmd;
12332
12333 /* If name contains a slash, don't use PATH or hash table */
12334 if (strchr(name, '/') != NULL) {
12335 entry->u.index = -1;
12336 if (act & DO_ABS) {
12337 while (stat(name, &statb) < 0) {
12338#ifdef SYSV
12339 if (errno == EINTR)
12340 continue;
12341#endif
12342 entry->cmdtype = CMDUNKNOWN;
12343 return;
12344 }
12345 }
12346 entry->cmdtype = CMDNORMAL;
12347 return;
12348 }
12349
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012350/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012351
12352 updatetbl = (path == pathval());
12353 if (!updatetbl) {
12354 act |= DO_ALTPATH;
12355 if (strstr(path, "%builtin") != NULL)
12356 act |= DO_ALTBLTIN;
12357 }
12358
12359 /* If name is in the table, check answer will be ok */
12360 cmdp = cmdlookup(name, 0);
12361 if (cmdp != NULL) {
12362 int bit;
12363
12364 switch (cmdp->cmdtype) {
12365 default:
12366#if DEBUG
12367 abort();
12368#endif
12369 case CMDNORMAL:
12370 bit = DO_ALTPATH;
12371 break;
12372 case CMDFUNCTION:
12373 bit = DO_NOFUNC;
12374 break;
12375 case CMDBUILTIN:
12376 bit = DO_ALTBLTIN;
12377 break;
12378 }
12379 if (act & bit) {
12380 updatetbl = 0;
12381 cmdp = NULL;
12382 } else if (cmdp->rehash == 0)
12383 /* if not invalidated by cd, we're done */
12384 goto success;
12385 }
12386
12387 /* If %builtin not in path, check for builtin next */
12388 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012389 if (bcmd) {
12390 if (IS_BUILTIN_REGULAR(bcmd))
12391 goto builtin_success;
12392 if (act & DO_ALTPATH) {
12393 if (!(act & DO_ALTBLTIN))
12394 goto builtin_success;
12395 } else if (builtinloc <= 0) {
12396 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012397 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012398 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012399
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012400#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012401 {
12402 int applet_no = find_applet_by_name(name);
12403 if (applet_no >= 0) {
12404 entry->cmdtype = CMDNORMAL;
12405 entry->u.index = -2 - applet_no;
12406 return;
12407 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012408 }
12409#endif
12410
Denis Vlasenkocc571512007-02-23 21:10:35 +000012411 /* We have to search path. */
12412 prev = -1; /* where to start */
12413 if (cmdp && cmdp->rehash) { /* doing a rehash */
12414 if (cmdp->cmdtype == CMDBUILTIN)
12415 prev = builtinloc;
12416 else
12417 prev = cmdp->param.index;
12418 }
12419
12420 e = ENOENT;
12421 idx = -1;
12422 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012423 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012424 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012425 /* NB: code below will still use fullname
12426 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012427 idx++;
12428 if (pathopt) {
12429 if (prefix(pathopt, "builtin")) {
12430 if (bcmd)
12431 goto builtin_success;
12432 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012433 }
12434 if ((act & DO_NOFUNC)
12435 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012436 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012437 continue;
12438 }
12439 }
12440 /* if rehash, don't redo absolute path names */
12441 if (fullname[0] == '/' && idx <= prev) {
12442 if (idx < prev)
12443 continue;
12444 TRACE(("searchexec \"%s\": no change\n", name));
12445 goto success;
12446 }
12447 while (stat(fullname, &statb) < 0) {
12448#ifdef SYSV
12449 if (errno == EINTR)
12450 continue;
12451#endif
12452 if (errno != ENOENT && errno != ENOTDIR)
12453 e = errno;
12454 goto loop;
12455 }
12456 e = EACCES; /* if we fail, this will be the error */
12457 if (!S_ISREG(statb.st_mode))
12458 continue;
12459 if (pathopt) { /* this is a %func directory */
12460 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012461 /* NB: stalloc will return space pointed by fullname
12462 * (because we don't have any intervening allocations
12463 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012464 readcmdfile(fullname);
12465 cmdp = cmdlookup(name, 0);
12466 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12467 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12468 stunalloc(fullname);
12469 goto success;
12470 }
12471 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12472 if (!updatetbl) {
12473 entry->cmdtype = CMDNORMAL;
12474 entry->u.index = idx;
12475 return;
12476 }
12477 INT_OFF;
12478 cmdp = cmdlookup(name, 1);
12479 cmdp->cmdtype = CMDNORMAL;
12480 cmdp->param.index = idx;
12481 INT_ON;
12482 goto success;
12483 }
12484
12485 /* We failed. If there was an entry for this command, delete it */
12486 if (cmdp && updatetbl)
12487 delete_cmd_entry();
12488 if (act & DO_ERR)
12489 ash_msg("%s: %s", name, errmsg(e, "not found"));
12490 entry->cmdtype = CMDUNKNOWN;
12491 return;
12492
12493 builtin_success:
12494 if (!updatetbl) {
12495 entry->cmdtype = CMDBUILTIN;
12496 entry->u.cmd = bcmd;
12497 return;
12498 }
12499 INT_OFF;
12500 cmdp = cmdlookup(name, 1);
12501 cmdp->cmdtype = CMDBUILTIN;
12502 cmdp->param.cmd = bcmd;
12503 INT_ON;
12504 success:
12505 cmdp->rehash = 0;
12506 entry->cmdtype = cmdp->cmdtype;
12507 entry->u = cmdp->param;
12508}
12509
12510
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012511/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012512
Eric Andersencb57d552001-06-28 07:25:16 +000012513/*
Eric Andersencb57d552001-06-28 07:25:16 +000012514 * The trap builtin.
12515 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012516static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012517trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012518{
12519 char *action;
12520 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012521 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012522
Eric Andersenc470f442003-07-28 09:56:35 +000012523 nextopt(nullstr);
12524 ap = argptr;
12525 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012526 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012527 char *tr = trap_ptr[signo];
12528 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012529 /* note: bash adds "SIG", but only if invoked
12530 * as "bash". If called as "sh", or if set -o posix,
12531 * then it prints short signal names.
12532 * We are printing short names: */
12533 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012534 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012535 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012536 /* trap_ptr != trap only if we are in special-cased `trap` code.
12537 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012538 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012539 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012540 }
12541 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012542 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012543 if (trap_ptr != trap) {
12544 free(trap_ptr);
12545 trap_ptr = trap;
12546 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012547 */
Eric Andersencb57d552001-06-28 07:25:16 +000012548 return 0;
12549 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012550
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012551 action = NULL;
12552 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012553 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012554 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012555 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012556 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012557 if (signo < 0) {
12558 /* Mimic bash message exactly */
12559 ash_msg("%s: invalid signal specification", *ap);
12560 exitcode = 1;
12561 goto next;
12562 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012563 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012564 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012565 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012566 action = NULL;
12567 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012568 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012569 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012570 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012571 if (action)
12572 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012573 trap[signo] = action;
12574 if (signo != 0)
12575 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012576 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012577 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012578 ap++;
12579 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012580 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012581}
12582
Eric Andersenc470f442003-07-28 09:56:35 +000012583
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012584/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012585
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012586#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012587static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012588helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012589{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012590 unsigned col;
12591 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012592
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012593 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012594 "Built-in commands:\n"
12595 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012596 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012597 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012598 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012599 if (col > 60) {
12600 out1fmt("\n");
12601 col = 0;
12602 }
12603 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012604# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012605 {
12606 const char *a = applet_names;
12607 while (*a) {
12608 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12609 if (col > 60) {
12610 out1fmt("\n");
12611 col = 0;
12612 }
Ron Yorston2b919582016-04-08 11:57:20 +010012613 while (*a++ != '\0')
12614 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012615 }
12616 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012617# endif
Eric Andersenc470f442003-07-28 09:56:35 +000012618 out1fmt("\n\n");
12619 return EXIT_SUCCESS;
12620}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012621#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012622
Flemming Madsend96ffda2013-04-07 18:47:24 +020012623#if MAX_HISTORY
12624static int FAST_FUNC
12625historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12626{
12627 show_history(line_input_state);
12628 return EXIT_SUCCESS;
12629}
12630#endif
12631
Eric Andersencb57d552001-06-28 07:25:16 +000012632/*
Eric Andersencb57d552001-06-28 07:25:16 +000012633 * The export and readonly commands.
12634 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012635static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012636exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012637{
12638 struct var *vp;
12639 char *name;
12640 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012641 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012642 char opt;
12643 int flag;
12644 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012645
Denys Vlasenkod5275882012-10-01 13:41:17 +020012646 /* "readonly" in bash accepts, but ignores -n.
12647 * We do the same: it saves a conditional in nextopt's param.
12648 */
12649 flag_off = 0;
12650 while ((opt = nextopt("np")) != '\0') {
12651 if (opt == 'n')
12652 flag_off = VEXPORT;
12653 }
12654 flag = VEXPORT;
12655 if (argv[0][0] == 'r') {
12656 flag = VREADONLY;
12657 flag_off = 0; /* readonly ignores -n */
12658 }
12659 flag_off = ~flag_off;
12660
12661 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12662 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012663 aptr = argptr;
12664 name = *aptr;
12665 if (name) {
12666 do {
12667 p = strchr(name, '=');
12668 if (p != NULL) {
12669 p++;
12670 } else {
12671 vp = *findvar(hashvar(name), name);
12672 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012673 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012674 continue;
12675 }
Eric Andersencb57d552001-06-28 07:25:16 +000012676 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012677 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012678 } while ((name = *++aptr) != NULL);
12679 return 0;
12680 }
Eric Andersencb57d552001-06-28 07:25:16 +000012681 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012682
12683 /* No arguments. Show the list of exported or readonly vars.
12684 * -n is ignored.
12685 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012686 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012687 return 0;
12688}
12689
Eric Andersencb57d552001-06-28 07:25:16 +000012690/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012691 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012692 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012693static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012694unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012695{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012696 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012697
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012698 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012699 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012700 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012701}
12702
Eric Andersencb57d552001-06-28 07:25:16 +000012703/*
Eric Andersencb57d552001-06-28 07:25:16 +000012704 * The unset builtin command. We unset the function before we unset the
12705 * variable to allow a function to be unset when there is a readonly variable
12706 * with the same name.
12707 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012708static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012709unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012710{
12711 char **ap;
12712 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012713 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012714 int ret = 0;
12715
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012716 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012717 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012718 }
Eric Andersencb57d552001-06-28 07:25:16 +000012719
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012720 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012721 if (flag != 'f') {
12722 i = unsetvar(*ap);
12723 ret |= i;
12724 if (!(i & 2))
12725 continue;
12726 }
12727 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012728 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012729 }
Eric Andersenc470f442003-07-28 09:56:35 +000012730 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012731}
12732
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012733static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012734 ' ', offsetof(struct tms, tms_utime),
12735 '\n', offsetof(struct tms, tms_stime),
12736 ' ', offsetof(struct tms, tms_cutime),
12737 '\n', offsetof(struct tms, tms_cstime),
12738 0
12739};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012740static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012741timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012742{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012743 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012744 const unsigned char *p;
12745 struct tms buf;
12746
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012747 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012748 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012749
12750 p = timescmd_str;
12751 do {
12752 t = *(clock_t *)(((char *) &buf) + p[1]);
12753 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012754 t = t % clk_tck;
12755 out1fmt("%lum%lu.%03lus%c",
12756 s / 60, s % 60,
12757 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012758 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012759 p += 2;
12760 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012761
Eric Andersencb57d552001-06-28 07:25:16 +000012762 return 0;
12763}
12764
Mike Frysinger98c52642009-04-02 10:02:37 +000012765#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012766/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012767 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012768 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012769 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012770 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012771 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012772static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012773letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012774{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012775 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012776
Denis Vlasenko68404f12008-03-17 09:00:54 +000012777 argv++;
12778 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012779 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012780 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012781 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012782 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012783
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012784 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012785}
Eric Andersenc470f442003-07-28 09:56:35 +000012786#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012787
Eric Andersenc470f442003-07-28 09:56:35 +000012788/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012789 * The read builtin. Options:
12790 * -r Do not interpret '\' specially
12791 * -s Turn off echo (tty only)
12792 * -n NCHARS Read NCHARS max
12793 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12794 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12795 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012796 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012797 * TODO: bash also has:
12798 * -a ARRAY Read into array[0],[1],etc
12799 * -d DELIM End on DELIM char, not newline
12800 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012801 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012802static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012803readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012804{
Denys Vlasenko73067272010-01-12 22:11:24 +010012805 char *opt_n = NULL;
12806 char *opt_p = NULL;
12807 char *opt_t = NULL;
12808 char *opt_u = NULL;
12809 int read_flags = 0;
12810 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012811 int i;
12812
Denys Vlasenko73067272010-01-12 22:11:24 +010012813 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012814 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012815 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012816 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012817 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012818 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012819 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012820 break;
12821 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012822 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012823 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012824 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012825 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012826 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012827 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012828 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012829 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012830 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012831 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012832 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012833 default:
12834 break;
12835 }
Eric Andersenc470f442003-07-28 09:56:35 +000012836 }
Paul Fox02eb9342005-09-07 16:56:02 +000012837
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012838 /* "read -s" needs to save/restore termios, can't allow ^C
12839 * to jump out of it.
12840 */
12841 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012842 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010012843 argptr,
12844 bltinlookup("IFS"), /* can be NULL */
12845 read_flags,
12846 opt_n,
12847 opt_p,
12848 opt_t,
12849 opt_u
12850 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012851 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012852
Denys Vlasenko73067272010-01-12 22:11:24 +010012853 if ((uintptr_t)r > 1)
12854 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012855
Denys Vlasenko73067272010-01-12 22:11:24 +010012856 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012857}
12858
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012859static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020012860umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012861{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012862 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000012863
Eric Andersenc470f442003-07-28 09:56:35 +000012864 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000012865 int symbolic_mode = 0;
12866
12867 while (nextopt("S") != '\0') {
12868 symbolic_mode = 1;
12869 }
12870
Denis Vlasenkob012b102007-02-19 22:43:01 +000012871 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012872 mask = umask(0);
12873 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012874 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000012875
Denys Vlasenko6283f982015-10-07 16:56:20 +020012876 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012877 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020012878 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000012879 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012880 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012881
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012882 i = 2;
12883 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020012884 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000012885 *p++ = permuser[i];
12886 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012887 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020012888 if (!(mask & 0400)) *p++ = 'r';
12889 if (!(mask & 0200)) *p++ = 'w';
12890 if (!(mask & 0100)) *p++ = 'x';
12891 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012892 if (--i < 0)
12893 break;
Eric Andersenc470f442003-07-28 09:56:35 +000012894 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012895 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020012896 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012897 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020012898 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000012899 }
12900 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020012901 char *modestr = *argptr;
12902 /* numeric umasks are taken as-is */
12903 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
12904 if (!isdigit(modestr[0]))
12905 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020012906 mask = bb_parse_mode(modestr, mask);
12907 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020012908 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000012909 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020012910 if (!isdigit(modestr[0]))
12911 mask ^= 0777;
12912 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000012913 }
12914 return 0;
12915}
12916
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012917static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012918ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012919{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012920 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012921}
12922
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012923/* ============ main() and helpers */
12924
12925/*
12926 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012927 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012928static void
12929exitshell(void)
12930{
12931 struct jmploc loc;
12932 char *p;
12933 int status;
12934
Denys Vlasenkobede2152011-09-04 16:12:33 +020012935#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
12936 save_history(line_input_state);
12937#endif
12938
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012939 status = exitstatus;
12940 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12941 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000012942 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012943/* dash bug: it just does _exit(exitstatus) here
12944 * but we have to do setjobctl(0) first!
12945 * (bug is still not fixed in dash-0.5.3 - if you run dash
12946 * under Midnight Commander, on exit from dash MC is backgrounded) */
12947 status = exitstatus;
12948 goto out;
12949 }
12950 exception_handler = &loc;
12951 p = trap[0];
12952 if (p) {
12953 trap[0] = NULL;
12954 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020012955 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012956 }
12957 flush_stdout_stderr();
12958 out:
12959 setjobctl(0);
12960 _exit(status);
12961 /* NOTREACHED */
12962}
12963
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012964static void
12965init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012966{
12967 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020012968 /* we will never free this */
12969 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012970
12971 /* from trap.c: */
12972 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010012973 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12974 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12975 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020012976 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012977
12978 /* from var.c: */
12979 {
12980 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012981 const char *p;
12982 struct stat st1, st2;
12983
12984 initvar();
12985 for (envp = environ; envp && *envp; envp++) {
12986 if (strchr(*envp, '=')) {
12987 setvareq(*envp, VEXPORT|VTEXTFIXED);
12988 }
12989 }
12990
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012991 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010012992#if ENABLE_ASH_BASH_COMPAT
12993 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010012994 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020012995 if (!lookupvar("HOSTNAME")) {
12996 struct utsname uts;
12997 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012998 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020012999 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013000#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013001 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013002 if (p) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013003 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013004 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13005 ) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013006 p = '\0';
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013007 }
13008 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013009 setpwd(p, 0);
13010 }
13011}
13012
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013013
13014//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013015//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013016//usage:#define ash_full_usage "\n\n"
13017//usage: "Unix shell interpreter"
13018
13019//usage:#if ENABLE_FEATURE_SH_IS_ASH
13020//usage:# define sh_trivial_usage ash_trivial_usage
13021//usage:# define sh_full_usage ash_full_usage
13022//usage:#endif
13023//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13024//usage:# define bash_trivial_usage ash_trivial_usage
13025//usage:# define bash_full_usage ash_full_usage
13026//usage:#endif
13027
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013028/*
13029 * Process the shell command line arguments.
13030 */
13031static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013032procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013033{
13034 int i;
13035 const char *xminusc;
13036 char **xargv;
13037
13038 xargv = argv;
13039 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013040 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013041 xargv++;
13042 for (i = 0; i < NOPTS; i++)
13043 optlist[i] = 2;
13044 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013045 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013046 /* it already printed err message */
13047 raise_exception(EXERROR);
13048 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013049 xargv = argptr;
13050 xminusc = minusc;
13051 if (*xargv == NULL) {
13052 if (xminusc)
13053 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13054 sflag = 1;
13055 }
13056 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13057 iflag = 1;
13058 if (mflag == 2)
13059 mflag = iflag;
13060 for (i = 0; i < NOPTS; i++)
13061 if (optlist[i] == 2)
13062 optlist[i] = 0;
13063#if DEBUG == 2
13064 debug = 1;
13065#endif
13066 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13067 if (xminusc) {
13068 minusc = *xargv++;
13069 if (*xargv)
13070 goto setarg0;
13071 } else if (!sflag) {
13072 setinputfile(*xargv, 0);
13073 setarg0:
13074 arg0 = *xargv++;
13075 commandname = arg0;
13076 }
13077
13078 shellparam.p = xargv;
13079#if ENABLE_ASH_GETOPTS
13080 shellparam.optind = 1;
13081 shellparam.optoff = -1;
13082#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013083 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013084 while (*xargv) {
13085 shellparam.nparam++;
13086 xargv++;
13087 }
13088 optschanged();
13089}
13090
13091/*
13092 * Read /etc/profile or .profile.
13093 */
13094static void
13095read_profile(const char *name)
13096{
13097 int skip;
13098
13099 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13100 return;
13101 skip = cmdloop(0);
13102 popfile();
13103 if (skip)
13104 exitshell();
13105}
13106
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013107/*
13108 * This routine is called when an error or an interrupt occurs in an
13109 * interactive shell and control is returned to the main command loop.
13110 */
13111static void
13112reset(void)
13113{
13114 /* from eval.c: */
13115 evalskip = 0;
13116 loopnest = 0;
13117 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013118 g_parsefile->left_in_buffer = 0;
13119 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013120 popallfiles();
13121 /* from parser.c: */
13122 tokpushback = 0;
13123 checkkwd = 0;
13124 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013125 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013126}
13127
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013128#if PROFILE
13129static short profile_buf[16384];
13130extern int etext();
13131#endif
13132
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013133/*
13134 * Main routine. We initialize things, parse the arguments, execute
13135 * profiles if we're a login shell, and then call cmdloop to execute
13136 * commands. The setjmp call sets up the location to jump to when an
13137 * exception occurs. When an exception occurs the variable "state"
13138 * is used to figure out how far we had gotten.
13139 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013140int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013141int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013142{
Mike Frysinger98c52642009-04-02 10:02:37 +000013143 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013144 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013145 struct jmploc jmploc;
13146 struct stackmark smark;
13147
Denis Vlasenko01631112007-12-16 17:20:38 +000013148 /* Initialize global data */
13149 INIT_G_misc();
13150 INIT_G_memstack();
13151 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013152#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013153 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013154#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013155 INIT_G_cmdtable();
13156
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013157#if PROFILE
13158 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13159#endif
13160
13161#if ENABLE_FEATURE_EDITING
13162 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13163#endif
13164 state = 0;
13165 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013166 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013167 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013168
13169 reset();
13170
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013171 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013172 if (e == EXERROR)
13173 exitstatus = 2;
13174 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013175 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013176 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013177 }
13178 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013179 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013180 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013181
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013182 popstackmark(&smark);
13183 FORCE_INT_ON; /* enable interrupts */
13184 if (s == 1)
13185 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013186 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013187 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013188 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013189 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013190 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013191 }
13192 exception_handler = &jmploc;
13193#if DEBUG
13194 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013195 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013196 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013197#endif
13198 rootpid = getpid();
13199
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013200 init();
13201 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013202 procargs(argv);
13203
Denys Vlasenko6088e132010-12-25 23:58:42 +010013204 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013205 isloginsh = 1;
13206 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013207 const char *hp;
13208
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013209 state = 1;
13210 read_profile("/etc/profile");
13211 state1:
13212 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013213 hp = lookupvar("HOME");
13214 if (hp) {
13215 hp = concat_path_file(hp, ".profile");
13216 read_profile(hp);
13217 free((char*)hp);
13218 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013219 }
13220 state2:
13221 state = 3;
13222 if (
13223#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013224 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013225#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013226 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013227 ) {
13228 shinit = lookupvar("ENV");
13229 if (shinit != NULL && *shinit != '\0') {
13230 read_profile(shinit);
13231 }
13232 }
13233 state3:
13234 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013235 if (minusc) {
13236 /* evalstring pushes parsefile stack.
13237 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013238 * is one of stacked source fds.
13239 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013240 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013241 // ^^ not necessary since now we special-case fd 0
13242 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013243 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013244 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013245
13246 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013247#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013248 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013249 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013250 if (!hp) {
13251 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013252 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013253 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013254 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013255 free((char*)hp);
13256 hp = lookupvar("HISTFILE");
13257 }
13258 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013259 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013260 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013261# if ENABLE_FEATURE_SH_HISTFILESIZE
13262 hp = lookupvar("HISTFILESIZE");
13263 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13264# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013265 }
13266#endif
13267 state4: /* XXX ??? - why isn't this before the "if" statement */
13268 cmdloop(1);
13269 }
13270#if PROFILE
13271 monitor(0);
13272#endif
13273#ifdef GPROF
13274 {
13275 extern void _mcleanup(void);
13276 _mcleanup();
13277 }
13278#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013279 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013280 exitshell();
13281 /* NOTREACHED */
13282}
13283
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013284
Eric Andersendf82f612001-06-28 07:46:40 +000013285/*-
13286 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013287 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013288 *
13289 * This code is derived from software contributed to Berkeley by
13290 * Kenneth Almquist.
13291 *
13292 * Redistribution and use in source and binary forms, with or without
13293 * modification, are permitted provided that the following conditions
13294 * are met:
13295 * 1. Redistributions of source code must retain the above copyright
13296 * notice, this list of conditions and the following disclaimer.
13297 * 2. Redistributions in binary form must reproduce the above copyright
13298 * notice, this list of conditions and the following disclaimer in the
13299 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013300 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013301 * may be used to endorse or promote products derived from this software
13302 * without specific prior written permission.
13303 *
13304 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13305 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13306 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13307 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13308 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13309 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13310 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13311 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13312 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13313 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13314 * SUCH DAMAGE.
13315 */