blob: 9fd1b55e2272d53637dd35e317fe489d74d5df82 [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 Vlasenkob3f29b42016-09-21 16:25:58 +020042#include <glob.h>
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020043#include <sys/times.h>
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020044#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko73067272010-01-12 22:11:24 +010045
Denys Vlasenko20704f02011-03-23 17:59:27 +010046#include "busybox.h" /* for applet_names */
47#include "unicode.h"
48
Denys Vlasenko73067272010-01-12 22:11:24 +010049#include "shell_common.h"
Denys Vlasenko26777aa2010-11-22 23:49:10 +010050#if ENABLE_SH_MATH_SUPPORT
51# include "math.h"
52#endif
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020053#if ENABLE_ASH_RANDOM_SUPPORT
54# include "random.h"
Denys Vlasenko36df0482009-10-19 16:07:28 +020055#else
56# define CLEAR_RANDOM_T(rnd) ((void)0)
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020057#endif
Denis Vlasenko61befda2008-11-25 01:36:03 +000058
Denys Vlasenko1fcbff22010-06-26 02:40:08 +020059#include "NUM_APPLETS.h"
Denys Vlasenko14974842010-03-23 01:08:26 +010060#if NUM_APPLETS == 1
Denis Vlasenko61befda2008-11-25 01:36:03 +000061/* STANDALONE does not make sense, and won't compile */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020062# undef CONFIG_FEATURE_SH_STANDALONE
63# undef ENABLE_FEATURE_SH_STANDALONE
64# undef IF_FEATURE_SH_STANDALONE
Denys Vlasenko14974842010-03-23 01:08:26 +010065# undef IF_NOT_FEATURE_SH_STANDALONE
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020066# define ENABLE_FEATURE_SH_STANDALONE 0
67# define IF_FEATURE_SH_STANDALONE(...)
68# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
Eric Andersencb57d552001-06-28 07:25:16 +000069#endif
70
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000071#ifndef PIPE_BUF
Denis Vlasenko653d8e72009-03-19 21:59:35 +000072# define PIPE_BUF 4096 /* amount of buffering in a pipe */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000073#endif
74
Denys Vlasenko153fcaa2010-02-21 05:17:41 +010075#if !BB_MMU
Denis Vlasenko653d8e72009-03-19 21:59:35 +000076# error "Do not even bother, ash will not run on NOMMU machine"
Denis Vlasenkob012b102007-02-19 22:43:01 +000077#endif
78
Denys Vlasenko771f1992010-07-16 14:31:34 +020079//config:config ASH
80//config: bool "ash"
81//config: default y
82//config: depends on !NOMMU
83//config: help
84//config: Tha 'ash' shell adds about 60k in the default configuration and is
85//config: the most complete and most pedantically correct shell included with
86//config: busybox. This shell is actually a derivative of the Debian 'dash'
87//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
88//config: (written by Kenneth Almquist) from NetBSD.
89//config:
90//config:config ASH_BASH_COMPAT
91//config: bool "bash-compatible extensions"
92//config: default y
93//config: depends on ASH
94//config: help
95//config: Enable bash-compatible extensions.
96//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010097//config:config ASH_IDLE_TIMEOUT
98//config: bool "Idle timeout variable"
99//config: default n
100//config: depends on ASH
101//config: help
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100102//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko046341e2011-02-04 17:53:59 +0100103//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config:config ASH_JOB_CONTROL
105//config: bool "Job control"
106//config: default y
107//config: depends on ASH
108//config: help
109//config: Enable job control in the ash shell.
110//config:
111//config:config ASH_ALIAS
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100112//config: bool "Alias support"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200113//config: default y
114//config: depends on ASH
115//config: help
116//config: Enable alias support in the ash shell.
117//config:
118//config:config ASH_GETOPTS
119//config: bool "Builtin getopt to parse positional parameters"
120//config: default y
121//config: depends on ASH
122//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100123//config: Enable support for getopts builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200124//config:
125//config:config ASH_BUILTIN_ECHO
126//config: bool "Builtin version of 'echo'"
127//config: default y
128//config: depends on ASH
129//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100130//config: Enable support for echo builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config:
132//config:config ASH_BUILTIN_PRINTF
133//config: bool "Builtin version of 'printf'"
134//config: default y
135//config: depends on ASH
136//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100137//config: Enable support for printf builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200138//config:
139//config:config ASH_BUILTIN_TEST
140//config: bool "Builtin version of 'test'"
141//config: default y
142//config: depends on ASH
143//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100144//config: Enable support for test builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200145//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200146//config:config ASH_HELP
147//config: bool "help builtin"
148//config: default y
149//config: depends on ASH
150//config: help
151//config: Enable help builtin in ash.
152//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200153//config:config ASH_CMDCMD
154//config: bool "'command' command to override shell builtins"
155//config: default y
156//config: depends on ASH
157//config: help
158//config: Enable support for the ash 'command' builtin, which allows
159//config: you to run the specified command with the specified arguments,
160//config: even when there is an ash builtin command with the same name.
161//config:
162//config:config ASH_MAIL
163//config: bool "Check for new mail on interactive shells"
164//config: default n
165//config: depends on ASH
166//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100167//config: Enable "check for new mail" function in the ash shell.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200168//config:
169//config:config ASH_OPTIMIZE_FOR_SIZE
170//config: bool "Optimize for size instead of speed"
171//config: default y
172//config: depends on ASH
173//config: help
174//config: Compile ash for reduced size at the price of speed.
175//config:
176//config:config ASH_RANDOM_SUPPORT
177//config: bool "Pseudorandom generator and $RANDOM variable"
178//config: default y
179//config: depends on ASH
180//config: help
181//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
182//config: Each read of "$RANDOM" will generate a new pseudorandom value.
183//config: You can reset the generator by using a specified start value.
184//config: After "unset RANDOM" the generator will switch off and this
185//config: variable will no longer have special treatment.
186//config:
187//config:config ASH_EXPAND_PRMT
188//config: bool "Expand prompt string"
189//config: default y
190//config: depends on ASH
191//config: help
192//config: "PS#" may contain volatile content, such as backquote commands.
193//config: This option recreates the prompt string from the environment
194//config: variable each time it is displayed.
Denys Vlasenko51ca7762010-07-16 17:16:40 +0200195//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200196
Denys Vlasenko20704f02011-03-23 17:59:27 +0100197//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
198//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
199//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
200
201//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
202//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
203
Denis Vlasenkob012b102007-02-19 22:43:01 +0000204
Denis Vlasenko01631112007-12-16 17:20:38 +0000205/* ============ Hash table sizes. Configurable. */
206
207#define VTABSIZE 39
208#define ATABSIZE 39
209#define CMDTABLESIZE 31 /* should be prime */
210
211
Denis Vlasenkob012b102007-02-19 22:43:01 +0000212/* ============ Shell options */
213
214static const char *const optletters_optnames[] = {
215 "e" "errexit",
216 "f" "noglob",
217 "I" "ignoreeof",
218 "i" "interactive",
219 "m" "monitor",
220 "n" "noexec",
221 "s" "stdin",
222 "x" "xtrace",
223 "v" "verbose",
224 "C" "noclobber",
225 "a" "allexport",
226 "b" "notify",
227 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100228 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100229#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100230 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100231#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000232#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000233 ,"\0" "nolog"
234 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000235#endif
236};
237
Denys Vlasenko285ad152009-12-04 23:02:27 +0100238#define optletters(n) optletters_optnames[n][0]
239#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000240
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000241enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000242
Eric Andersenc470f442003-07-28 09:56:35 +0000243
Denis Vlasenkob012b102007-02-19 22:43:01 +0000244/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000245
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200246#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000247
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000248/*
Eric Andersenc470f442003-07-28 09:56:35 +0000249 * We enclose jmp_buf in a structure so that we can declare pointers to
250 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000251 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000252 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000253 * exception handlers, the user should save the value of handler on entry
254 * to an inner scope, set handler to point to a jmploc structure for the
255 * inner scope, and restore handler on exit from the scope.
256 */
Eric Andersenc470f442003-07-28 09:56:35 +0000257struct jmploc {
258 jmp_buf loc;
259};
Denis Vlasenko01631112007-12-16 17:20:38 +0000260
261struct globals_misc {
262 /* pid of main shell */
263 int rootpid;
264 /* shell level: 0 for the main shell, 1 for its children, and so on */
265 int shlvl;
266#define rootshell (!shlvl)
267 char *minusc; /* argument to -c option */
268
269 char *curdir; // = nullstr; /* current working directory */
270 char *physdir; // = nullstr; /* physical working directory */
271
272 char *arg0; /* value of $0 */
273
274 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000275
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200276 volatile int suppress_int; /* counter */
277 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000278 /* last pending signal */
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200279 volatile /*sig_atomic_t*/ smallint pending_sig;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000280 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000281 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000282#define EXINT 0 /* SIGINT received */
283#define EXERROR 1 /* a generic error */
284#define EXSHELLPROC 2 /* execute a shell procedure */
285#define EXEXEC 3 /* command execution failed */
286#define EXEXIT 4 /* exit the shell */
287#define EXSIG 5 /* trapped signal in wait(1) */
Eric Andersen2870d962001-07-02 17:27:21 +0000288
Denis Vlasenko01631112007-12-16 17:20:38 +0000289 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000290 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000291
292 char optlist[NOPTS];
293#define eflag optlist[0]
294#define fflag optlist[1]
295#define Iflag optlist[2]
296#define iflag optlist[3]
297#define mflag optlist[4]
298#define nflag optlist[5]
299#define sflag optlist[6]
300#define xflag optlist[7]
301#define vflag optlist[8]
302#define Cflag optlist[9]
303#define aflag optlist[10]
304#define bflag optlist[11]
305#define uflag optlist[12]
306#define viflag optlist[13]
Michael Abbott359da5e2009-12-04 23:03:29 +0100307#if ENABLE_ASH_BASH_COMPAT
308# define pipefail optlist[14]
309#else
310# define pipefail 0
311#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000312#if DEBUG
Michael Abbott359da5e2009-12-04 23:03:29 +0100313# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
314# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000315#endif
316
317 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000318 /*
319 * Sigmode records the current value of the signal handlers for the various
320 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000321 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000322 */
323 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000324#define S_DFL 1 /* default signal handling (SIG_DFL) */
325#define S_CATCH 2 /* signal is caught */
326#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denys Vlasenkoe5814a52016-07-16 18:33:55 +0200327#define S_HARD_IGN 4 /* signal is ignored permanently */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000328
Denis Vlasenko01631112007-12-16 17:20:38 +0000329 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000330 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200331 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000332 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200333 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000334
335 /* Rarely referenced stuff */
336#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200337 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000338#endif
339 pid_t backgndpid; /* pid of last background process */
340 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
Denis Vlasenko01631112007-12-16 17:20:38 +0000341};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000342extern struct globals_misc *const ash_ptr_to_globals_misc;
343#define G_misc (*ash_ptr_to_globals_misc)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000344#define rootpid (G_misc.rootpid )
345#define shlvl (G_misc.shlvl )
346#define minusc (G_misc.minusc )
347#define curdir (G_misc.curdir )
348#define physdir (G_misc.physdir )
349#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000350#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000351#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200352#define suppress_int (G_misc.suppress_int )
353#define pending_int (G_misc.pending_int )
354#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000355#define isloginsh (G_misc.isloginsh )
356#define nullstr (G_misc.nullstr )
357#define optlist (G_misc.optlist )
358#define sigmode (G_misc.sigmode )
359#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200360#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000361#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200362#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200363#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000364#define backgndpid (G_misc.backgndpid )
365#define job_warning (G_misc.job_warning)
Denis Vlasenko01631112007-12-16 17:20:38 +0000366#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000367 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
368 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000369 curdir = nullstr; \
370 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200371 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000372} while (0)
373
374
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000375/* ============ DEBUG */
376#if DEBUG
377static void trace_printf(const char *fmt, ...);
378static void trace_vprintf(const char *fmt, va_list va);
379# define TRACE(param) trace_printf param
380# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000381# define close(fd) do { \
382 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000383 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200384 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000385 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000386} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000387#else
388# define TRACE(param)
389# define TRACEV(param)
390#endif
391
392
Denis Vlasenko559691a2008-10-05 18:39:31 +0000393/* ============ Utility functions */
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000394#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
395
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100396#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
397#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
398
Denis Vlasenko559691a2008-10-05 18:39:31 +0000399static int isdigit_str9(const char *str)
400{
401 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
402 while (--maxlen && isdigit(*str))
403 str++;
404 return (*str == '\0');
405}
Denis Vlasenko01631112007-12-16 17:20:38 +0000406
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200407static const char *var_end(const char *var)
408{
409 while (*var)
410 if (*var++ == '=')
411 break;
412 return var;
413}
414
Denis Vlasenko559691a2008-10-05 18:39:31 +0000415
416/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100417
418static void exitshell(void) NORETURN;
419
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000420/*
Eric Andersen2870d962001-07-02 17:27:21 +0000421 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000422 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000423 * much more efficient and portable. (But hacking the kernel is so much
424 * more fun than worrying about efficiency and portability. :-))
425 */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000426#define INT_OFF do { \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200427 suppress_int++; \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000428 xbarrier(); \
429} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000430
431/*
432 * Called to raise an exception. Since C doesn't include exceptions, we
433 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000434 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000435 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000436static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000437static void
438raise_exception(int e)
439{
440#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000441 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000442 abort();
443#endif
444 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000445 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000446 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000447}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000448#if DEBUG
449#define raise_exception(e) do { \
450 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
451 raise_exception(e); \
452} while (0)
453#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000454
455/*
456 * Called from trap.c when a SIGINT is received. (If the user specifies
457 * that SIGINT is to be trapped or ignored using the trap builtin, then
458 * this routine is not called.) Suppressint is nonzero when interrupts
459 * are held using the INT_OFF macro. (The test for iflag is just
460 * defensive programming.)
461 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000462static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000463static void
464raise_interrupt(void)
465{
Denis Vlasenko4b875702009-03-19 13:30:04 +0000466 int ex_type;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000467
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200468 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000469 /* Signal is not automatically unmasked after it is raised,
470 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000471 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200472 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000473
Denis Vlasenko4b875702009-03-19 13:30:04 +0000474 ex_type = EXSIG;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000475 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
476 if (!(rootshell && iflag)) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000477 /* Kill ourself with SIGINT */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000478 signal(SIGINT, SIG_DFL);
479 raise(SIGINT);
480 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000481 ex_type = EXINT;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000482 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000483 raise_exception(ex_type);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000484 /* NOTREACHED */
485}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000486#if DEBUG
487#define raise_interrupt() do { \
488 TRACE(("raising interrupt on line %d\n", __LINE__)); \
489 raise_interrupt(); \
490} while (0)
491#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000492
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000493static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000494int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000495{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000496 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200497 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000498 raise_interrupt();
499 }
500}
501#define INT_ON int_on()
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000502static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000503force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000504{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000505 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200506 suppress_int = 0;
507 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000508 raise_interrupt();
509}
510#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000511
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200512#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000513
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000514#define RESTORE_INT(v) do { \
515 xbarrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200516 suppress_int = (v); \
517 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000518 raise_interrupt(); \
519} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000520
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000521
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000522/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000523
Eric Andersenc470f442003-07-28 09:56:35 +0000524static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000525outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000526{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000527 INT_OFF;
528 fputs(p, file);
529 INT_ON;
530}
531
532static void
533flush_stdout_stderr(void)
534{
535 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100536 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000537 INT_ON;
538}
539
Denys Vlasenko9c541002015-10-07 15:44:36 +0200540/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000541static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200542newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000543{
544 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200545 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000546 fflush(dest);
547 INT_ON;
548}
549
550static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
551static int
552out1fmt(const char *fmt, ...)
553{
554 va_list ap;
555 int r;
556
557 INT_OFF;
558 va_start(ap, fmt);
559 r = vprintf(fmt, ap);
560 va_end(ap);
561 INT_ON;
562 return r;
563}
564
565static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
566static int
567fmtstr(char *outbuf, size_t length, const char *fmt, ...)
568{
569 va_list ap;
570 int ret;
571
572 va_start(ap, fmt);
573 INT_OFF;
574 ret = vsnprintf(outbuf, length, fmt, ap);
575 va_end(ap);
576 INT_ON;
577 return ret;
578}
579
580static void
581out1str(const char *p)
582{
583 outstr(p, stdout);
584}
585
586static void
587out2str(const char *p)
588{
589 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100590 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000591}
592
593
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000594/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000595
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000596/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100597#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200598#define CTLESC ((unsigned char)'\201') /* escape next character */
599#define CTLVAR ((unsigned char)'\202') /* variable defn */
600#define CTLENDVAR ((unsigned char)'\203')
601#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200602#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
603#define CTLENDARI ((unsigned char)'\207')
604#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100605#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000606
607/* variable substitution byte (follows CTLVAR) */
608#define VSTYPE 0x0f /* type of variable substitution */
609#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000610
611/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000612#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
613#define VSMINUS 0x2 /* ${var-text} */
614#define VSPLUS 0x3 /* ${var+text} */
615#define VSQUESTION 0x4 /* ${var?message} */
616#define VSASSIGN 0x5 /* ${var=text} */
617#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
618#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
619#define VSTRIMLEFT 0x8 /* ${var#pattern} */
620#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
621#define VSLENGTH 0xa /* ${#var} */
622#if ENABLE_ASH_BASH_COMPAT
623#define VSSUBSTR 0xc /* ${var:position:length} */
624#define VSREPLACE 0xd /* ${var/pattern/replacement} */
625#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
626#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000627
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000628static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200629 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000630};
Ron Yorston549deab2015-05-18 09:57:51 +0200631#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000632
Denis Vlasenko559691a2008-10-05 18:39:31 +0000633#define NCMD 0
634#define NPIPE 1
635#define NREDIR 2
636#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000637#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000638#define NAND 5
639#define NOR 6
640#define NSEMI 7
641#define NIF 8
642#define NWHILE 9
643#define NUNTIL 10
644#define NFOR 11
645#define NCASE 12
646#define NCLIST 13
647#define NDEFUN 14
648#define NARG 15
649#define NTO 16
650#if ENABLE_ASH_BASH_COMPAT
651#define NTO2 17
652#endif
653#define NCLOBBER 18
654#define NFROM 19
655#define NFROMTO 20
656#define NAPPEND 21
657#define NTOFD 22
658#define NFROMFD 23
659#define NHERE 24
660#define NXHERE 25
661#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000662#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000663
664union node;
665
666struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000667 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000668 union node *assign;
669 union node *args;
670 union node *redirect;
671};
672
673struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000674 smallint type;
675 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000676 struct nodelist *cmdlist;
677};
678
679struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000680 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000681 union node *n;
682 union node *redirect;
683};
684
685struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000686 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000687 union node *ch1;
688 union node *ch2;
689};
690
691struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000692 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000693 union node *test;
694 union node *ifpart;
695 union node *elsepart;
696};
697
698struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000699 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000700 union node *args;
701 union node *body;
702 char *var;
703};
704
705struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000706 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000707 union node *expr;
708 union node *cases;
709};
710
711struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000712 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000713 union node *next;
714 union node *pattern;
715 union node *body;
716};
717
718struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000719 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000720 union node *next;
721 char *text;
722 struct nodelist *backquote;
723};
724
Denis Vlasenko559691a2008-10-05 18:39:31 +0000725/* nfile and ndup layout must match!
726 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
727 * that it is actually NTO2 (>&file), and change its type.
728 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000729struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000730 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000731 union node *next;
732 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000733 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000734 union node *fname;
735 char *expfname;
736};
737
738struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000739 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000740 union node *next;
741 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000742 int dupfd;
743 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000744 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000745};
746
747struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000748 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000749 union node *next;
750 int fd;
751 union node *doc;
752};
753
754struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000755 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000756 union node *com;
757};
758
759union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000760 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000761 struct ncmd ncmd;
762 struct npipe npipe;
763 struct nredir nredir;
764 struct nbinary nbinary;
765 struct nif nif;
766 struct nfor nfor;
767 struct ncase ncase;
768 struct nclist nclist;
769 struct narg narg;
770 struct nfile nfile;
771 struct ndup ndup;
772 struct nhere nhere;
773 struct nnot nnot;
774};
775
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200776/*
777 * NODE_EOF is returned by parsecmd when it encounters an end of file.
778 * It must be distinct from NULL.
779 */
780#define NODE_EOF ((union node *) -1L)
781
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000782struct nodelist {
783 struct nodelist *next;
784 union node *n;
785};
786
787struct funcnode {
788 int count;
789 union node n;
790};
791
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000792/*
793 * Free a parse tree.
794 */
795static void
796freefunc(struct funcnode *f)
797{
798 if (f && --f->count < 0)
799 free(f);
800}
801
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000802
803/* ============ Debugging output */
804
805#if DEBUG
806
807static FILE *tracefile;
808
809static void
810trace_printf(const char *fmt, ...)
811{
812 va_list va;
813
814 if (debug != 1)
815 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000816 if (DEBUG_TIME)
817 fprintf(tracefile, "%u ", (int) time(NULL));
818 if (DEBUG_PID)
819 fprintf(tracefile, "[%u] ", (int) getpid());
820 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200821 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000822 va_start(va, fmt);
823 vfprintf(tracefile, fmt, va);
824 va_end(va);
825}
826
827static void
828trace_vprintf(const char *fmt, va_list va)
829{
830 if (debug != 1)
831 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000832 if (DEBUG_TIME)
833 fprintf(tracefile, "%u ", (int) time(NULL));
834 if (DEBUG_PID)
835 fprintf(tracefile, "[%u] ", (int) getpid());
836 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200837 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000838 vfprintf(tracefile, fmt, va);
839}
840
841static void
842trace_puts(const char *s)
843{
844 if (debug != 1)
845 return;
846 fputs(s, tracefile);
847}
848
849static void
850trace_puts_quoted(char *s)
851{
852 char *p;
853 char c;
854
855 if (debug != 1)
856 return;
857 putc('"', tracefile);
858 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100859 switch ((unsigned char)*p) {
860 case '\n': c = 'n'; goto backslash;
861 case '\t': c = 't'; goto backslash;
862 case '\r': c = 'r'; goto backslash;
863 case '\"': c = '\"'; goto backslash;
864 case '\\': c = '\\'; goto backslash;
865 case CTLESC: c = 'e'; goto backslash;
866 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100867 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000868 backslash:
869 putc('\\', tracefile);
870 putc(c, tracefile);
871 break;
872 default:
873 if (*p >= ' ' && *p <= '~')
874 putc(*p, tracefile);
875 else {
876 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100877 putc((*p >> 6) & 03, tracefile);
878 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000879 putc(*p & 07, tracefile);
880 }
881 break;
882 }
883 }
884 putc('"', tracefile);
885}
886
887static void
888trace_puts_args(char **ap)
889{
890 if (debug != 1)
891 return;
892 if (!*ap)
893 return;
894 while (1) {
895 trace_puts_quoted(*ap);
896 if (!*++ap) {
897 putc('\n', tracefile);
898 break;
899 }
900 putc(' ', tracefile);
901 }
902}
903
904static void
905opentrace(void)
906{
907 char s[100];
908#ifdef O_APPEND
909 int flags;
910#endif
911
912 if (debug != 1) {
913 if (tracefile)
914 fflush(tracefile);
915 /* leave open because libedit might be using it */
916 return;
917 }
918 strcpy(s, "./trace");
919 if (tracefile) {
920 if (!freopen(s, "a", tracefile)) {
921 fprintf(stderr, "Can't re-open %s\n", s);
922 debug = 0;
923 return;
924 }
925 } else {
926 tracefile = fopen(s, "a");
927 if (tracefile == NULL) {
928 fprintf(stderr, "Can't open %s\n", s);
929 debug = 0;
930 return;
931 }
932 }
933#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000934 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000935 if (flags >= 0)
936 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
937#endif
938 setlinebuf(tracefile);
939 fputs("\nTracing started.\n", tracefile);
940}
941
942static void
943indent(int amount, char *pfx, FILE *fp)
944{
945 int i;
946
947 for (i = 0; i < amount; i++) {
948 if (pfx && i == amount - 1)
949 fputs(pfx, fp);
950 putc('\t', fp);
951 }
952}
953
954/* little circular references here... */
955static void shtree(union node *n, int ind, char *pfx, FILE *fp);
956
957static void
958sharg(union node *arg, FILE *fp)
959{
960 char *p;
961 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100962 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000963
964 if (arg->type != NARG) {
965 out1fmt("<node type %d>\n", arg->type);
966 abort();
967 }
968 bqlist = arg->narg.backquote;
969 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100970 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000971 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700972 p++;
973 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000974 break;
975 case CTLVAR:
976 putc('$', fp);
977 putc('{', fp);
978 subtype = *++p;
979 if (subtype == VSLENGTH)
980 putc('#', fp);
981
Dan Fandrich77d48722010-09-07 23:38:28 -0700982 while (*p != '=') {
983 putc(*p, fp);
984 p++;
985 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000986
987 if (subtype & VSNUL)
988 putc(':', fp);
989
990 switch (subtype & VSTYPE) {
991 case VSNORMAL:
992 putc('}', fp);
993 break;
994 case VSMINUS:
995 putc('-', fp);
996 break;
997 case VSPLUS:
998 putc('+', fp);
999 break;
1000 case VSQUESTION:
1001 putc('?', fp);
1002 break;
1003 case VSASSIGN:
1004 putc('=', fp);
1005 break;
1006 case VSTRIMLEFT:
1007 putc('#', fp);
1008 break;
1009 case VSTRIMLEFTMAX:
1010 putc('#', fp);
1011 putc('#', fp);
1012 break;
1013 case VSTRIMRIGHT:
1014 putc('%', fp);
1015 break;
1016 case VSTRIMRIGHTMAX:
1017 putc('%', fp);
1018 putc('%', fp);
1019 break;
1020 case VSLENGTH:
1021 break;
1022 default:
1023 out1fmt("<subtype %d>", subtype);
1024 }
1025 break;
1026 case CTLENDVAR:
1027 putc('}', fp);
1028 break;
1029 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001030 putc('$', fp);
1031 putc('(', fp);
1032 shtree(bqlist->n, -1, NULL, fp);
1033 putc(')', fp);
1034 break;
1035 default:
1036 putc(*p, fp);
1037 break;
1038 }
1039 }
1040}
1041
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001042static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001043shcmd(union node *cmd, FILE *fp)
1044{
1045 union node *np;
1046 int first;
1047 const char *s;
1048 int dftfd;
1049
1050 first = 1;
1051 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001052 if (!first)
1053 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001054 sharg(np, fp);
1055 first = 0;
1056 }
1057 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001058 if (!first)
1059 putc(' ', fp);
1060 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001061 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001062 case NTO: s = ">>"+1; dftfd = 1; break;
1063 case NCLOBBER: s = ">|"; dftfd = 1; break;
1064 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001065#if ENABLE_ASH_BASH_COMPAT
1066 case NTO2:
1067#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001068 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001069 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001070 case NFROMFD: s = "<&"; break;
1071 case NFROMTO: s = "<>"; break;
1072 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001073 }
1074 if (np->nfile.fd != dftfd)
1075 fprintf(fp, "%d", np->nfile.fd);
1076 fputs(s, fp);
1077 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1078 fprintf(fp, "%d", np->ndup.dupfd);
1079 } else {
1080 sharg(np->nfile.fname, fp);
1081 }
1082 first = 0;
1083 }
1084}
1085
1086static void
1087shtree(union node *n, int ind, char *pfx, FILE *fp)
1088{
1089 struct nodelist *lp;
1090 const char *s;
1091
1092 if (n == NULL)
1093 return;
1094
1095 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001096
1097 if (n == NODE_EOF) {
1098 fputs("<EOF>", fp);
1099 return;
1100 }
1101
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001102 switch (n->type) {
1103 case NSEMI:
1104 s = "; ";
1105 goto binop;
1106 case NAND:
1107 s = " && ";
1108 goto binop;
1109 case NOR:
1110 s = " || ";
1111 binop:
1112 shtree(n->nbinary.ch1, ind, NULL, fp);
1113 /* if (ind < 0) */
1114 fputs(s, fp);
1115 shtree(n->nbinary.ch2, ind, NULL, fp);
1116 break;
1117 case NCMD:
1118 shcmd(n, fp);
1119 if (ind >= 0)
1120 putc('\n', fp);
1121 break;
1122 case NPIPE:
1123 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001124 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001125 if (lp->next)
1126 fputs(" | ", fp);
1127 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001128 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001129 fputs(" &", fp);
1130 if (ind >= 0)
1131 putc('\n', fp);
1132 break;
1133 default:
1134 fprintf(fp, "<node type %d>", n->type);
1135 if (ind >= 0)
1136 putc('\n', fp);
1137 break;
1138 }
1139}
1140
1141static void
1142showtree(union node *n)
1143{
1144 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001145 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001146}
1147
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001148#endif /* DEBUG */
1149
1150
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001151/* ============ Parser data */
1152
1153/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001154 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1155 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001156struct strlist {
1157 struct strlist *next;
1158 char *text;
1159};
1160
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001161struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001162
Denis Vlasenkob012b102007-02-19 22:43:01 +00001163struct strpush {
1164 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001165 char *prev_string;
1166 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001167#if ENABLE_ASH_ALIAS
1168 struct alias *ap; /* if push was associated with an alias */
1169#endif
1170 char *string; /* remember the string since it may change */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001171
1172 /* Remember last two characters for pungetc. */
1173 int lastc[2];
1174
1175 /* Number of outstanding calls to pungetc. */
1176 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001177};
1178
1179struct parsefile {
1180 struct parsefile *prev; /* preceding file on stack */
1181 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001182 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001183 int left_in_line; /* number of chars left in this line */
1184 int left_in_buffer; /* number of chars left in this buffer past the line */
1185 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001186 char *buf; /* input buffer */
1187 struct strpush *strpush; /* for pushing strings at this level */
1188 struct strpush basestrpush; /* so pushing one is fast */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02001189
1190 /* Remember last two characters for pungetc. */
1191 int lastc[2];
1192
1193 /* Number of outstanding calls to pungetc. */
1194 int unget;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001195};
1196
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001197static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001198static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001199static int startlinno; /* line # where last token started */
1200static char *commandname; /* currently executing command */
1201static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001202static uint8_t exitstatus; /* exit status of last command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001203
1204
1205/* ============ Message printing */
1206
1207static void
1208ash_vmsg(const char *msg, va_list ap)
1209{
1210 fprintf(stderr, "%s: ", arg0);
1211 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001212 if (strcmp(arg0, commandname))
1213 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001214 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001215 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001216 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001217 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001218 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001219}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001220
1221/*
1222 * Exverror is called to raise the error exception. If the second argument
1223 * is not NULL then error prints an error message using printf style
1224 * formatting. It then raises the error exception.
1225 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001226static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001227static void
1228ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001229{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001230#if DEBUG
1231 if (msg) {
1232 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1233 TRACEV((msg, ap));
1234 TRACE(("\") pid=%d\n", getpid()));
1235 } else
1236 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1237 if (msg)
1238#endif
1239 ash_vmsg(msg, ap);
1240
1241 flush_stdout_stderr();
1242 raise_exception(cond);
1243 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001244}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001245
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001246static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001247static void
1248ash_msg_and_raise_error(const char *msg, ...)
1249{
1250 va_list ap;
1251
1252 va_start(ap, msg);
1253 ash_vmsg_and_raise(EXERROR, msg, ap);
1254 /* NOTREACHED */
1255 va_end(ap);
1256}
1257
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001258static void raise_error_syntax(const char *) NORETURN;
1259static void
1260raise_error_syntax(const char *msg)
1261{
1262 ash_msg_and_raise_error("syntax error: %s", msg);
1263 /* NOTREACHED */
1264}
1265
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001266static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001267static void
1268ash_msg_and_raise(int cond, const char *msg, ...)
1269{
1270 va_list ap;
1271
1272 va_start(ap, msg);
1273 ash_vmsg_and_raise(cond, msg, ap);
1274 /* NOTREACHED */
1275 va_end(ap);
1276}
1277
1278/*
1279 * error/warning routines for external builtins
1280 */
1281static void
1282ash_msg(const char *fmt, ...)
1283{
1284 va_list ap;
1285
1286 va_start(ap, fmt);
1287 ash_vmsg(fmt, ap);
1288 va_end(ap);
1289}
1290
1291/*
1292 * Return a string describing an error. The returned string may be a
1293 * pointer to a static buffer that will be overwritten on the next call.
1294 * Action describes the operation that got the error.
1295 */
1296static const char *
1297errmsg(int e, const char *em)
1298{
1299 if (e == ENOENT || e == ENOTDIR) {
1300 return em;
1301 }
1302 return strerror(e);
1303}
1304
1305
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001306/* ============ Memory allocation */
1307
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001308#if 0
1309/* I consider these wrappers nearly useless:
1310 * ok, they return you to nearest exception handler, but
1311 * how much memory do you leak in the process, making
1312 * memory starvation worse?
1313 */
1314static void *
1315ckrealloc(void * p, size_t nbytes)
1316{
1317 p = realloc(p, nbytes);
1318 if (!p)
1319 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1320 return p;
1321}
1322
1323static void *
1324ckmalloc(size_t nbytes)
1325{
1326 return ckrealloc(NULL, nbytes);
1327}
1328
1329static void *
1330ckzalloc(size_t nbytes)
1331{
1332 return memset(ckmalloc(nbytes), 0, nbytes);
1333}
1334
1335static char *
1336ckstrdup(const char *s)
1337{
1338 char *p = strdup(s);
1339 if (!p)
1340 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1341 return p;
1342}
1343#else
1344/* Using bbox equivalents. They exit if out of memory */
1345# define ckrealloc xrealloc
1346# define ckmalloc xmalloc
1347# define ckzalloc xzalloc
1348# define ckstrdup xstrdup
1349#endif
1350
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001351/*
1352 * It appears that grabstackstr() will barf with such alignments
1353 * because stalloc() will return a string allocated in a new stackblock.
1354 */
1355#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1356enum {
1357 /* Most machines require the value returned from malloc to be aligned
1358 * in some way. The following macro will get this right
1359 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001360 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001361 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001362 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001363};
1364
1365struct stack_block {
1366 struct stack_block *prev;
1367 char space[MINSIZE];
1368};
1369
1370struct stackmark {
1371 struct stack_block *stackp;
1372 char *stacknxt;
1373 size_t stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001374};
1375
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001376
Denis Vlasenko01631112007-12-16 17:20:38 +00001377struct globals_memstack {
1378 struct stack_block *g_stackp; // = &stackbase;
Denis Vlasenko01631112007-12-16 17:20:38 +00001379 char *g_stacknxt; // = stackbase.space;
1380 char *sstrend; // = stackbase.space + MINSIZE;
1381 size_t g_stacknleft; // = MINSIZE;
1382 int herefd; // = -1;
1383 struct stack_block stackbase;
1384};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001385extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1386#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001387#define g_stackp (G_memstack.g_stackp )
Denis Vlasenko01631112007-12-16 17:20:38 +00001388#define g_stacknxt (G_memstack.g_stacknxt )
1389#define sstrend (G_memstack.sstrend )
1390#define g_stacknleft (G_memstack.g_stacknleft)
1391#define herefd (G_memstack.herefd )
1392#define stackbase (G_memstack.stackbase )
1393#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001394 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1395 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001396 g_stackp = &stackbase; \
1397 g_stacknxt = stackbase.space; \
1398 g_stacknleft = MINSIZE; \
1399 sstrend = stackbase.space + MINSIZE; \
1400 herefd = -1; \
1401} while (0)
1402
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001403
Denis Vlasenko01631112007-12-16 17:20:38 +00001404#define stackblock() ((void *)g_stacknxt)
1405#define stackblocksize() g_stacknleft
1406
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001407/*
1408 * Parse trees for commands are allocated in lifo order, so we use a stack
1409 * to make this more efficient, and also to avoid all sorts of exception
1410 * handling code to handle interrupts in the middle of a parse.
1411 *
1412 * The size 504 was chosen because the Ultrix malloc handles that size
1413 * well.
1414 */
1415static void *
1416stalloc(size_t nbytes)
1417{
1418 char *p;
1419 size_t aligned;
1420
1421 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001422 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001423 size_t len;
1424 size_t blocksize;
1425 struct stack_block *sp;
1426
1427 blocksize = aligned;
1428 if (blocksize < MINSIZE)
1429 blocksize = MINSIZE;
1430 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1431 if (len < blocksize)
1432 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1433 INT_OFF;
1434 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001435 sp->prev = g_stackp;
1436 g_stacknxt = sp->space;
1437 g_stacknleft = blocksize;
1438 sstrend = g_stacknxt + blocksize;
1439 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001440 INT_ON;
1441 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001442 p = g_stacknxt;
1443 g_stacknxt += aligned;
1444 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001445 return p;
1446}
1447
Denis Vlasenko597906c2008-02-20 16:38:54 +00001448static void *
1449stzalloc(size_t nbytes)
1450{
1451 return memset(stalloc(nbytes), 0, nbytes);
1452}
1453
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001454static void
1455stunalloc(void *p)
1456{
1457#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001458 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001459 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001460 abort();
1461 }
1462#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001463 g_stacknleft += g_stacknxt - (char *)p;
1464 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001465}
1466
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001467/*
1468 * Like strdup but works with the ash stack.
1469 */
1470static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001471sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001472{
1473 size_t len = strlen(p) + 1;
1474 return memcpy(stalloc(len), p, len);
1475}
1476
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001477static void
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001478grabstackblock(size_t len)
1479{
1480 len = SHELL_ALIGN(len);
1481 g_stacknxt += len;
1482 g_stacknleft -= len;
1483}
1484
1485static void
1486pushstackmark(struct stackmark *mark, size_t len)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001487{
Denis Vlasenko01631112007-12-16 17:20:38 +00001488 mark->stackp = g_stackp;
1489 mark->stacknxt = g_stacknxt;
1490 mark->stacknleft = g_stacknleft;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02001491 grabstackblock(len);
1492}
1493
1494static void
1495setstackmark(struct stackmark *mark)
1496{
1497 pushstackmark(mark, g_stacknxt == g_stackp->space && g_stackp != &stackbase);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001498}
1499
1500static void
1501popstackmark(struct stackmark *mark)
1502{
1503 struct stack_block *sp;
1504
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001505 if (!mark->stackp)
1506 return;
1507
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001508 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001509 while (g_stackp != mark->stackp) {
1510 sp = g_stackp;
1511 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001512 free(sp);
1513 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001514 g_stacknxt = mark->stacknxt;
1515 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001516 sstrend = mark->stacknxt + mark->stacknleft;
1517 INT_ON;
1518}
1519
1520/*
1521 * When the parser reads in a string, it wants to stick the string on the
1522 * stack and only adjust the stack pointer when it knows how big the
1523 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1524 * of space on top of the stack and stackblocklen returns the length of
1525 * this block. Growstackblock will grow this space by at least one byte,
1526 * possibly moving it (like realloc). Grabstackblock actually allocates the
1527 * part of the block that has been used.
1528 */
1529static void
1530growstackblock(void)
1531{
1532 size_t newlen;
1533
Denis Vlasenko01631112007-12-16 17:20:38 +00001534 newlen = g_stacknleft * 2;
1535 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001536 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1537 if (newlen < 128)
1538 newlen += 128;
1539
Denis Vlasenko01631112007-12-16 17:20:38 +00001540 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001541 struct stack_block *sp;
1542 struct stack_block *prevstackp;
1543 size_t grosslen;
1544
1545 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001546 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001547 prevstackp = sp->prev;
1548 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1549 sp = ckrealloc(sp, grosslen);
1550 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001551 g_stackp = sp;
1552 g_stacknxt = sp->space;
1553 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001554 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001555 INT_ON;
1556 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001557 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001558 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001559 char *p = stalloc(newlen);
1560
1561 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001562 g_stacknxt = memcpy(p, oldspace, oldlen);
1563 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001564 }
1565}
1566
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001567/*
1568 * The following routines are somewhat easier to use than the above.
1569 * The user declares a variable of type STACKSTR, which may be declared
1570 * to be a register. The macro STARTSTACKSTR initializes things. Then
1571 * the user uses the macro STPUTC to add characters to the string. In
1572 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1573 * grown as necessary. When the user is done, she can just leave the
1574 * string there and refer to it using stackblock(). Or she can allocate
1575 * the space for it using grabstackstr(). If it is necessary to allow
1576 * someone else to use the stack temporarily and then continue to grow
1577 * the string, the user should use grabstack to allocate the space, and
1578 * then call ungrabstr(p) to return to the previous mode of operation.
1579 *
1580 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1581 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1582 * is space for at least one character.
1583 */
1584static void *
1585growstackstr(void)
1586{
1587 size_t len = stackblocksize();
1588 if (herefd >= 0 && len >= 1024) {
1589 full_write(herefd, stackblock(), len);
1590 return stackblock();
1591 }
1592 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001593 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001594}
1595
1596/*
1597 * Called from CHECKSTRSPACE.
1598 */
1599static char *
1600makestrspace(size_t newlen, char *p)
1601{
Denis Vlasenko01631112007-12-16 17:20:38 +00001602 size_t len = p - g_stacknxt;
Denys Vlasenko53d6e032016-09-30 11:24:12 +02001603 size_t size;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001604
1605 for (;;) {
1606 size_t nleft;
1607
1608 size = stackblocksize();
1609 nleft = size - len;
1610 if (nleft >= newlen)
1611 break;
1612 growstackblock();
1613 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001614 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001615}
1616
1617static char *
1618stack_nputstr(const char *s, size_t n, char *p)
1619{
1620 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001621 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001622 return p;
1623}
1624
1625static char *
1626stack_putstr(const char *s, char *p)
1627{
1628 return stack_nputstr(s, strlen(s), p);
1629}
1630
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001631static char *
1632_STPUTC(int c, char *p)
1633{
1634 if (p == sstrend)
1635 p = growstackstr();
1636 *p++ = c;
1637 return p;
1638}
1639
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001640#define STARTSTACKSTR(p) ((p) = stackblock())
1641#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001642#define CHECKSTRSPACE(n, p) do { \
1643 char *q = (p); \
1644 size_t l = (n); \
1645 size_t m = sstrend - q; \
1646 if (l > m) \
1647 (p) = makestrspace(l, q); \
1648} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001649#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001650#define STACKSTRNUL(p) do { \
1651 if ((p) == sstrend) \
1652 (p) = growstackstr(); \
1653 *(p) = '\0'; \
1654} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001655#define STUNPUTC(p) (--(p))
1656#define STTOPC(p) ((p)[-1])
1657#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001658
1659#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001660#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001661#define stackstrend() ((void *)sstrend)
1662
1663
1664/* ============ String helpers */
1665
1666/*
1667 * prefix -- see if pfx is a prefix of string.
1668 */
1669static char *
1670prefix(const char *string, const char *pfx)
1671{
1672 while (*pfx) {
1673 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001674 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001675 }
1676 return (char *) string;
1677}
1678
1679/*
1680 * Check for a valid number. This should be elsewhere.
1681 */
1682static int
1683is_number(const char *p)
1684{
1685 do {
1686 if (!isdigit(*p))
1687 return 0;
1688 } while (*++p != '\0');
1689 return 1;
1690}
1691
1692/*
1693 * Convert a string of digits to an integer, printing an error message on
1694 * failure.
1695 */
1696static int
1697number(const char *s)
1698{
1699 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001700 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001701 return atoi(s);
1702}
1703
1704/*
1705 * Produce a possibly single quoted string suitable as input to the shell.
1706 * The return string is allocated on the stack.
1707 */
1708static char *
1709single_quote(const char *s)
1710{
1711 char *p;
1712
1713 STARTSTACKSTR(p);
1714
1715 do {
1716 char *q;
1717 size_t len;
1718
1719 len = strchrnul(s, '\'') - s;
1720
1721 q = p = makestrspace(len + 3, p);
1722
1723 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001724 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001725 *q++ = '\'';
1726 s += len;
1727
1728 STADJUST(q - p, p);
1729
Denys Vlasenkocd716832009-11-28 22:14:02 +01001730 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001731 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001732 len = 0;
1733 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001734
1735 q = p = makestrspace(len + 3, p);
1736
1737 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001738 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001739 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001740
1741 STADJUST(q - p, p);
1742 } while (*s);
1743
Denys Vlasenkocd716832009-11-28 22:14:02 +01001744 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001745
1746 return stackblock();
1747}
1748
1749
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001750/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001751
1752static char **argptr; /* argument list for builtin commands */
1753static char *optionarg; /* set by nextopt (like getopt) */
1754static char *optptr; /* used by nextopt */
1755
1756/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001757 * XXX - should get rid of. Have all builtins use getopt(3).
1758 * The library getopt must have the BSD extension static variable
1759 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001760 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001761 * Standard option processing (a la getopt) for builtin routines.
1762 * The only argument that is passed to nextopt is the option string;
1763 * the other arguments are unnecessary. It returns the character,
1764 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001765 */
1766static int
1767nextopt(const char *optstring)
1768{
1769 char *p;
1770 const char *q;
1771 char c;
1772
1773 p = optptr;
1774 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001775 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001776 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001777 if (p == NULL)
1778 return '\0';
1779 if (*p != '-')
1780 return '\0';
1781 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001782 return '\0';
1783 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001784 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001785 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001786 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001787 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001788 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001789 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001790 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001792 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001793 if (*++q == ':')
1794 q++;
1795 }
1796 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001797 if (*p == '\0') {
1798 p = *argptr++;
1799 if (p == NULL)
1800 ash_msg_and_raise_error("no arg for -%c option", c);
1801 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001802 optionarg = p;
1803 p = NULL;
1804 }
1805 optptr = p;
1806 return c;
1807}
1808
1809
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001810/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001811
Denis Vlasenko01631112007-12-16 17:20:38 +00001812/*
1813 * The parsefile structure pointed to by the global variable parsefile
1814 * contains information about the current file being read.
1815 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001816struct shparam {
1817 int nparam; /* # of positional parameters (without $0) */
1818#if ENABLE_ASH_GETOPTS
1819 int optind; /* next parameter to be processed by getopts */
1820 int optoff; /* used by getopts */
1821#endif
1822 unsigned char malloced; /* if parameter list dynamically allocated */
1823 char **p; /* parameter list */
1824};
1825
1826/*
1827 * Free the list of positional parameters.
1828 */
1829static void
1830freeparam(volatile struct shparam *param)
1831{
Denis Vlasenko01631112007-12-16 17:20:38 +00001832 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001833 char **ap, **ap1;
1834 ap = ap1 = param->p;
1835 while (*ap)
1836 free(*ap++);
1837 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001838 }
1839}
1840
1841#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001842static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001843#endif
1844
1845struct var {
1846 struct var *next; /* next entry in hash list */
1847 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001848 const char *var_text; /* name=value */
1849 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001850 /* the variable gets set/unset */
1851};
1852
1853struct localvar {
1854 struct localvar *next; /* next local variable in list */
1855 struct var *vp; /* the variable that was made local */
1856 int flags; /* saved flags */
1857 const char *text; /* saved text */
1858};
1859
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001860/* flags */
1861#define VEXPORT 0x01 /* variable is exported */
1862#define VREADONLY 0x02 /* variable cannot be modified */
1863#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1864#define VTEXTFIXED 0x08 /* text is statically allocated */
1865#define VSTACK 0x10 /* text is allocated on the stack */
1866#define VUNSET 0x20 /* the variable is not set */
1867#define VNOFUNC 0x40 /* don't call the callback function */
1868#define VNOSET 0x80 /* do not set variable - just readonly test */
1869#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001870#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001871# define VDYNAMIC 0x200 /* dynamic variable */
1872#else
1873# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001874#endif
1875
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001876
Denis Vlasenko01631112007-12-16 17:20:38 +00001877/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001878#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001879static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001880change_lc_all(const char *value)
1881{
1882 if (value && *value != '\0')
1883 setlocale(LC_ALL, value);
1884}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001885static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001886change_lc_ctype(const char *value)
1887{
1888 if (value && *value != '\0')
1889 setlocale(LC_CTYPE, value);
1890}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001891#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001892#if ENABLE_ASH_MAIL
1893static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001894static void changemail(const char *var_value) FAST_FUNC;
1895#else
1896# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001897#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001898static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001899#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001900static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001901#endif
1902
Denis Vlasenko01631112007-12-16 17:20:38 +00001903static const struct {
1904 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001905 const char *var_text;
1906 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001907} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001908 /*
1909 * Note: VEXPORT would not work correctly here for NOFORK applets:
1910 * some environment strings may be constant.
1911 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001912 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001913#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001914 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1915 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001916#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001917 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1918 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1919 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1920 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001921#if ENABLE_ASH_GETOPTS
Denis Vlasenko01631112007-12-16 17:20:38 +00001922 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001923#endif
1924#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001925 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001926#endif
1927#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001928 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1929 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001930#endif
1931#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001932 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001933#endif
1934};
1935
Denis Vlasenko0b769642008-07-24 07:54:57 +00001936struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001937
1938struct globals_var {
1939 struct shparam shellparam; /* $@ current positional parameters */
1940 struct redirtab *redirlist;
1941 int g_nullredirs;
1942 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1943 struct var *vartab[VTABSIZE];
1944 struct var varinit[ARRAY_SIZE(varinit_data)];
1945};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001946extern struct globals_var *const ash_ptr_to_globals_var;
1947#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001948#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001949//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001950#define g_nullredirs (G_var.g_nullredirs )
1951#define preverrout_fd (G_var.preverrout_fd)
1952#define vartab (G_var.vartab )
1953#define varinit (G_var.varinit )
1954#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001955 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001956 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1957 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001958 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001959 varinit[i].flags = varinit_data[i].flags; \
1960 varinit[i].var_text = varinit_data[i].var_text; \
1961 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001962 } \
1963} while (0)
1964
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001965#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001966#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001967# define vmail (&vifs)[1]
1968# define vmpath (&vmail)[1]
1969# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001970#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001971# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001972#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001973#define vps1 (&vpath)[1]
1974#define vps2 (&vps1)[1]
1975#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001976#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001977# define voptind (&vps4)[1]
1978# if ENABLE_ASH_RANDOM_SUPPORT
1979# define vrandom (&voptind)[1]
1980# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001981#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001982# if ENABLE_ASH_RANDOM_SUPPORT
1983# define vrandom (&vps4)[1]
1984# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001985#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001986
1987/*
1988 * The following macros access the values of the above variables.
1989 * They have to skip over the name. They return the null string
1990 * for unset variables.
1991 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001992#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001993#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001994#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001995# define mailval() (vmail.var_text + 5)
1996# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001997# define mpathset() ((vmpath.flags & VUNSET) == 0)
1998#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001999#define pathval() (vpath.var_text + 5)
2000#define ps1val() (vps1.var_text + 4)
2001#define ps2val() (vps2.var_text + 4)
2002#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002003#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002004# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002005#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002006
Denis Vlasenko01631112007-12-16 17:20:38 +00002007#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002008static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002009getoptsreset(const char *value)
2010{
2011 shellparam.optind = number(value);
2012 shellparam.optoff = -1;
2013}
2014#endif
2015
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002016/*
2017 * Compares two strings up to the first = or '\0'. The first
2018 * string must be terminated by '='; the second may be terminated by
2019 * either '=' or '\0'.
2020 */
2021static int
2022varcmp(const char *p, const char *q)
2023{
2024 int c, d;
2025
2026 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002027 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002028 goto out;
2029 p++;
2030 q++;
2031 }
2032 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002033 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002034 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002035 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002036 out:
2037 return c - d;
2038}
2039
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002040/*
2041 * Find the appropriate entry in the hash table from the name.
2042 */
2043static struct var **
2044hashvar(const char *p)
2045{
2046 unsigned hashval;
2047
2048 hashval = ((unsigned char) *p) << 4;
2049 while (*p && *p != '=')
2050 hashval += (unsigned char) *p++;
2051 return &vartab[hashval % VTABSIZE];
2052}
2053
2054static int
2055vpcmp(const void *a, const void *b)
2056{
2057 return varcmp(*(const char **)a, *(const char **)b);
2058}
2059
2060/*
2061 * This routine initializes the builtin variables.
2062 */
2063static void
2064initvar(void)
2065{
2066 struct var *vp;
2067 struct var *end;
2068 struct var **vpp;
2069
2070 /*
2071 * PS1 depends on uid
2072 */
2073#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002074 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002075#else
2076 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002077 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002078#endif
2079 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002080 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002081 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002082 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002083 vp->next = *vpp;
2084 *vpp = vp;
2085 } while (++vp < end);
2086}
2087
2088static struct var **
2089findvar(struct var **vpp, const char *name)
2090{
2091 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002092 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002093 break;
2094 }
2095 }
2096 return vpp;
2097}
2098
2099/*
2100 * Find the value of a variable. Returns NULL if not set.
2101 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002102static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002103lookupvar(const char *name)
2104{
2105 struct var *v;
2106
2107 v = *findvar(hashvar(name), name);
2108 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002109#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002110 /*
2111 * Dynamic variables are implemented roughly the same way they are
2112 * in bash. Namely, they're "special" so long as they aren't unset.
2113 * As soon as they're unset, they're no longer dynamic, and dynamic
2114 * lookup will no longer happen at that point. -- PFM.
2115 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002116 if (v->flags & VDYNAMIC)
2117 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002118#endif
2119 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002120 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002121 }
2122 return NULL;
2123}
2124
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002125static void reinit_unicode_for_ash(void)
2126{
2127 /* Unicode support should be activated even if LANG is set
2128 * _during_ shell execution, not only if it was set when
2129 * shell was started. Therefore, re-check LANG every time:
2130 */
2131 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2132 || ENABLE_UNICODE_USING_LOCALE
2133 ) {
2134 const char *s = lookupvar("LC_ALL");
2135 if (!s) s = lookupvar("LC_CTYPE");
2136 if (!s) s = lookupvar("LANG");
2137 reinit_unicode(s);
2138 }
2139}
2140
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002141/*
2142 * Search the environment of a builtin command.
2143 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002144static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002145bltinlookup(const char *name)
2146{
2147 struct strlist *sp;
2148
2149 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002150 if (varcmp(sp->text, name) == 0)
2151 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002152 }
2153 return lookupvar(name);
2154}
2155
2156/*
2157 * Same as setvar except that the variable and value are passed in
2158 * the first argument as name=value. Since the first argument will
2159 * be actually stored in the table, it should not be a string that
2160 * will go away.
2161 * Called with interrupts off.
2162 */
2163static void
2164setvareq(char *s, int flags)
2165{
2166 struct var *vp, **vpp;
2167
2168 vpp = hashvar(s);
2169 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2170 vp = *findvar(vpp, s);
2171 if (vp) {
2172 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2173 const char *n;
2174
2175 if (flags & VNOSAVE)
2176 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002177 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002178 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2179 }
2180
2181 if (flags & VNOSET)
2182 return;
2183
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002184 if (vp->var_func && !(flags & VNOFUNC))
2185 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002186
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002187 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2188 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002189
2190 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2191 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002192 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002193 if (flags & VNOSET)
2194 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002195 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002196 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002197 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002198 *vpp = vp;
2199 }
2200 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2201 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002202 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002203 vp->flags = flags;
2204}
2205
2206/*
2207 * Set the value of a variable. The flags argument is ored with the
2208 * flags of the variable. If val is NULL, the variable is unset.
2209 */
2210static void
2211setvar(const char *name, const char *val, int flags)
2212{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002213 const char *q;
2214 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002215 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002216 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002217 size_t vallen;
2218
2219 q = endofname(name);
2220 p = strchrnul(q, '=');
2221 namelen = p - name;
2222 if (!namelen || p != q)
2223 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2224 vallen = 0;
2225 if (val == NULL) {
2226 flags |= VUNSET;
2227 } else {
2228 vallen = strlen(val);
2229 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002230
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002231 INT_OFF;
2232 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002233 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002234 if (val) {
2235 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002236 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002237 }
2238 *p = '\0';
2239 setvareq(nameeq, flags | VNOSAVE);
2240 INT_ON;
2241}
2242
Denys Vlasenko03dad222010-01-12 23:29:57 +01002243static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002244setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002245{
2246 setvar(name, val, 0);
2247}
2248
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002249#if ENABLE_ASH_GETOPTS
2250/*
2251 * Safe version of setvar, returns 1 on success 0 on failure.
2252 */
2253static int
2254setvarsafe(const char *name, const char *val, int flags)
2255{
2256 int err;
2257 volatile int saveint;
2258 struct jmploc *volatile savehandler = exception_handler;
2259 struct jmploc jmploc;
2260
2261 SAVE_INT(saveint);
2262 if (setjmp(jmploc.loc))
2263 err = 1;
2264 else {
2265 exception_handler = &jmploc;
2266 setvar(name, val, flags);
2267 err = 0;
2268 }
2269 exception_handler = savehandler;
2270 RESTORE_INT(saveint);
2271 return err;
2272}
2273#endif
2274
2275/*
2276 * Unset the specified variable.
2277 */
2278static int
2279unsetvar(const char *s)
2280{
2281 struct var **vpp;
2282 struct var *vp;
2283 int retval;
2284
2285 vpp = findvar(hashvar(s), s);
2286 vp = *vpp;
2287 retval = 2;
2288 if (vp) {
2289 int flags = vp->flags;
2290
2291 retval = 1;
2292 if (flags & VREADONLY)
2293 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002294#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002295 vp->flags &= ~VDYNAMIC;
2296#endif
2297 if (flags & VUNSET)
2298 goto ok;
2299 if ((flags & VSTRFIXED) == 0) {
2300 INT_OFF;
2301 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002302 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002303 *vpp = vp->next;
2304 free(vp);
2305 INT_ON;
2306 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002307 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002308 vp->flags &= ~VEXPORT;
2309 }
2310 ok:
2311 retval = 0;
2312 }
2313 out:
2314 return retval;
2315}
2316
2317/*
2318 * Process a linked list of variable assignments.
2319 */
2320static void
2321listsetvar(struct strlist *list_set_var, int flags)
2322{
2323 struct strlist *lp = list_set_var;
2324
2325 if (!lp)
2326 return;
2327 INT_OFF;
2328 do {
2329 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002330 lp = lp->next;
2331 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002332 INT_ON;
2333}
2334
2335/*
2336 * Generate a list of variables satisfying the given conditions.
2337 */
2338static char **
2339listvars(int on, int off, char ***end)
2340{
2341 struct var **vpp;
2342 struct var *vp;
2343 char **ep;
2344 int mask;
2345
2346 STARTSTACKSTR(ep);
2347 vpp = vartab;
2348 mask = on | off;
2349 do {
2350 for (vp = *vpp; vp; vp = vp->next) {
2351 if ((vp->flags & mask) == on) {
2352 if (ep == stackstrend())
2353 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002354 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002355 }
2356 }
2357 } while (++vpp < vartab + VTABSIZE);
2358 if (ep == stackstrend())
2359 ep = growstackstr();
2360 if (end)
2361 *end = ep;
2362 *ep++ = NULL;
2363 return grabstackstr(ep);
2364}
2365
2366
2367/* ============ Path search helper
2368 *
2369 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002370 * of the path before the first call; path_advance will update
2371 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002372 * the possible path expansions in sequence. If an option (indicated by
2373 * a percent sign) appears in the path entry then the global variable
2374 * pathopt will be set to point to it; otherwise pathopt will be set to
2375 * NULL.
2376 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002377static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002378
2379static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002380path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002381{
2382 const char *p;
2383 char *q;
2384 const char *start;
2385 size_t len;
2386
2387 if (*path == NULL)
2388 return NULL;
2389 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002390 for (p = start; *p && *p != ':' && *p != '%'; p++)
2391 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002392 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2393 while (stackblocksize() < len)
2394 growstackblock();
2395 q = stackblock();
2396 if (p != start) {
2397 memcpy(q, start, p - start);
2398 q += p - start;
2399 *q++ = '/';
2400 }
2401 strcpy(q, name);
2402 pathopt = NULL;
2403 if (*p == '%') {
2404 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002405 while (*p && *p != ':')
2406 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002407 }
2408 if (*p == ':')
2409 *path = p + 1;
2410 else
2411 *path = NULL;
2412 return stalloc(len);
2413}
2414
2415
2416/* ============ Prompt */
2417
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002418static smallint doprompt; /* if set, prompt the user */
2419static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002420
2421#if ENABLE_FEATURE_EDITING
2422static line_input_t *line_input_state;
2423static const char *cmdedit_prompt;
2424static void
2425putprompt(const char *s)
2426{
2427 if (ENABLE_ASH_EXPAND_PRMT) {
2428 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002429 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002430 return;
2431 }
2432 cmdedit_prompt = s;
2433}
2434#else
2435static void
2436putprompt(const char *s)
2437{
2438 out2str(s);
2439}
2440#endif
2441
2442#if ENABLE_ASH_EXPAND_PRMT
2443/* expandstr() needs parsing machinery, so it is far away ahead... */
2444static const char *expandstr(const char *ps);
2445#else
2446#define expandstr(s) s
2447#endif
2448
2449static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002450setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002451{
2452 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002453 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2454
2455 if (!do_set)
2456 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002457
2458 needprompt = 0;
2459
2460 switch (whichprompt) {
2461 case 1:
2462 prompt = ps1val();
2463 break;
2464 case 2:
2465 prompt = ps2val();
2466 break;
2467 default: /* 0 */
2468 prompt = nullstr;
2469 }
2470#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002471 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002472#endif
2473 putprompt(expandstr(prompt));
2474#if ENABLE_ASH_EXPAND_PRMT
2475 popstackmark(&smark);
2476#endif
2477}
2478
2479
2480/* ============ The cd and pwd commands */
2481
2482#define CD_PHYSICAL 1
2483#define CD_PRINT 2
2484
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002485static int
2486cdopt(void)
2487{
2488 int flags = 0;
2489 int i, j;
2490
2491 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002492 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002493 if (i != j) {
2494 flags ^= CD_PHYSICAL;
2495 j = i;
2496 }
2497 }
2498
2499 return flags;
2500}
2501
2502/*
2503 * Update curdir (the name of the current directory) in response to a
2504 * cd command.
2505 */
2506static const char *
2507updatepwd(const char *dir)
2508{
2509 char *new;
2510 char *p;
2511 char *cdcomppath;
2512 const char *lim;
2513
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002514 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002515 STARTSTACKSTR(new);
2516 if (*dir != '/') {
2517 if (curdir == nullstr)
2518 return 0;
2519 new = stack_putstr(curdir, new);
2520 }
2521 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002522 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002523 if (*dir != '/') {
2524 if (new[-1] != '/')
2525 USTPUTC('/', new);
2526 if (new > lim && *lim == '/')
2527 lim++;
2528 } else {
2529 USTPUTC('/', new);
2530 cdcomppath++;
2531 if (dir[1] == '/' && dir[2] != '/') {
2532 USTPUTC('/', new);
2533 cdcomppath++;
2534 lim++;
2535 }
2536 }
2537 p = strtok(cdcomppath, "/");
2538 while (p) {
2539 switch (*p) {
2540 case '.':
2541 if (p[1] == '.' && p[2] == '\0') {
2542 while (new > lim) {
2543 STUNPUTC(new);
2544 if (new[-1] == '/')
2545 break;
2546 }
2547 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002548 }
2549 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002550 break;
2551 /* fall through */
2552 default:
2553 new = stack_putstr(p, new);
2554 USTPUTC('/', new);
2555 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002556 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002557 }
2558 if (new > lim)
2559 STUNPUTC(new);
2560 *new = 0;
2561 return stackblock();
2562}
2563
2564/*
2565 * Find out what the current directory is. If we already know the current
2566 * directory, this routine returns immediately.
2567 */
2568static char *
2569getpwd(void)
2570{
Denis Vlasenko01631112007-12-16 17:20:38 +00002571 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002572 return dir ? dir : nullstr;
2573}
2574
2575static void
2576setpwd(const char *val, int setold)
2577{
2578 char *oldcur, *dir;
2579
2580 oldcur = dir = curdir;
2581
2582 if (setold) {
2583 setvar("OLDPWD", oldcur, VEXPORT);
2584 }
2585 INT_OFF;
2586 if (physdir != nullstr) {
2587 if (physdir != oldcur)
2588 free(physdir);
2589 physdir = nullstr;
2590 }
2591 if (oldcur == val || !val) {
2592 char *s = getpwd();
2593 physdir = s;
2594 if (!val)
2595 dir = s;
2596 } else
2597 dir = ckstrdup(val);
2598 if (oldcur != dir && oldcur != nullstr) {
2599 free(oldcur);
2600 }
2601 curdir = dir;
2602 INT_ON;
2603 setvar("PWD", dir, VEXPORT);
2604}
2605
2606static void hashcd(void);
2607
2608/*
2609 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2610 * know that the current directory has changed.
2611 */
2612static int
2613docd(const char *dest, int flags)
2614{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002615 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002616 int err;
2617
2618 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2619
2620 INT_OFF;
2621 if (!(flags & CD_PHYSICAL)) {
2622 dir = updatepwd(dest);
2623 if (dir)
2624 dest = dir;
2625 }
2626 err = chdir(dest);
2627 if (err)
2628 goto out;
2629 setpwd(dir, 1);
2630 hashcd();
2631 out:
2632 INT_ON;
2633 return err;
2634}
2635
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002636static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002637cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002638{
2639 const char *dest;
2640 const char *path;
2641 const char *p;
2642 char c;
2643 struct stat statb;
2644 int flags;
2645
2646 flags = cdopt();
2647 dest = *argptr;
2648 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002649 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002650 else if (LONE_DASH(dest)) {
2651 dest = bltinlookup("OLDPWD");
2652 flags |= CD_PRINT;
2653 }
2654 if (!dest)
2655 dest = nullstr;
2656 if (*dest == '/')
2657 goto step7;
2658 if (*dest == '.') {
2659 c = dest[1];
2660 dotdot:
2661 switch (c) {
2662 case '\0':
2663 case '/':
2664 goto step6;
2665 case '.':
2666 c = dest[2];
2667 if (c != '.')
2668 goto dotdot;
2669 }
2670 }
2671 if (!*dest)
2672 dest = ".";
2673 path = bltinlookup("CDPATH");
2674 if (!path) {
2675 step6:
2676 step7:
2677 p = dest;
2678 goto docd;
2679 }
2680 do {
2681 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002682 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002683 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2684 if (c && c != ':')
2685 flags |= CD_PRINT;
2686 docd:
2687 if (!docd(p, flags))
2688 goto out;
2689 break;
2690 }
2691 } while (path);
2692 ash_msg_and_raise_error("can't cd to %s", dest);
2693 /* NOTREACHED */
2694 out:
2695 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002696 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002697 return 0;
2698}
2699
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002700static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002701pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002702{
2703 int flags;
2704 const char *dir = curdir;
2705
2706 flags = cdopt();
2707 if (flags) {
2708 if (physdir == nullstr)
2709 setpwd(dir, 0);
2710 dir = physdir;
2711 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002712 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002713 return 0;
2714}
2715
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002716
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002717/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002718
Denis Vlasenko834dee72008-10-07 09:18:30 +00002719
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002720#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002721
Eric Andersenc470f442003-07-28 09:56:35 +00002722/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002723#define CWORD 0 /* character is nothing special */
2724#define CNL 1 /* newline character */
2725#define CBACK 2 /* a backslash character */
2726#define CSQUOTE 3 /* single quote */
2727#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002728#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002729#define CBQUOTE 6 /* backwards single quote */
2730#define CVAR 7 /* a dollar sign */
2731#define CENDVAR 8 /* a '}' character */
2732#define CLP 9 /* a left paren in arithmetic */
2733#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002734#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002735#define CCTL 12 /* like CWORD, except it must be escaped */
2736#define CSPCL 13 /* these terminate a word */
2737#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002738
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002739#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002740#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002741# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002742#endif
2743
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002744#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002745
Mike Frysinger98c52642009-04-02 10:02:37 +00002746#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002747# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002748#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002749# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002750#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002751static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002752#if ENABLE_ASH_ALIAS
2753 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2754#endif
2755 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2756 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2757 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2758 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2759 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2760 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2761 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2762 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2763 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2764 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2765 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002766#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002767 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2768 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2769 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2770#endif
2771#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002772};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002773/* Constants below must match table above */
2774enum {
2775#if ENABLE_ASH_ALIAS
2776 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2777#endif
2778 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2779 CNL_CNL_CNL_CNL , /* 2 */
2780 CWORD_CCTL_CCTL_CWORD , /* 3 */
2781 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2782 CVAR_CVAR_CWORD_CVAR , /* 5 */
2783 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2784 CSPCL_CWORD_CWORD_CLP , /* 7 */
2785 CSPCL_CWORD_CWORD_CRP , /* 8 */
2786 CBACK_CBACK_CCTL_CBACK , /* 9 */
2787 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2788 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2789 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2790 CWORD_CWORD_CWORD_CWORD , /* 13 */
2791 CCTL_CCTL_CCTL_CCTL , /* 14 */
2792};
Eric Andersen2870d962001-07-02 17:27:21 +00002793
Denys Vlasenkocd716832009-11-28 22:14:02 +01002794/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2795 * caller must ensure proper cast on it if c is *char_ptr!
2796 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002797/* Values for syntax param */
2798#define BASESYNTAX 0 /* not in quotes */
2799#define DQSYNTAX 1 /* in double quotes */
2800#define SQSYNTAX 2 /* in single quotes */
2801#define ARISYNTAX 3 /* in arithmetic */
2802#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002803
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002804#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002805
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002806static int
2807SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002808{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002809 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2810 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2811 /*
2812 * This causes '/' to be prepended with CTLESC in dquoted string,
2813 * making "./file"* treated incorrectly because we feed
2814 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2815 * The "homegrown" glob implementation is okay with that,
2816 * but glibc one isn't. With '/' always treated as CWORD,
2817 * both work fine.
2818 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002819# if ENABLE_ASH_ALIAS
2820 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002821 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002822 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002823 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2824 11, 3 /* "}~" */
2825 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002826# else
2827 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002828 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002829 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002830 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2831 10, 2 /* "}~" */
2832 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002833# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002834 const char *s;
2835 int indx;
2836
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002837 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002838 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002839# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002840 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002841 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002842 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002843# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002844 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002845 /* Cast is purely for paranoia here,
2846 * just in case someone passed signed char to us */
2847 if ((unsigned char)c >= CTL_FIRST
2848 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002849 ) {
2850 return CCTL;
2851 }
2852 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002853 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002854 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002855 indx = syntax_index_table[s - spec_symbls];
2856 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002857 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002858}
2859
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002860#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002861
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002862static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002863 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002864 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2874 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2875 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2897 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2898 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2899 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2901 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2902 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2903 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2904 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2905 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2906 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2907 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2909 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2910 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002911/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2912 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002913 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2925 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2926 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2927 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2928 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2929 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2957 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2958 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2959 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2962 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2990 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2991 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2992 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2993 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2994 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2995 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2996 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2997 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2998 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2999 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3000 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3001 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3002 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003121 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003122# if ENABLE_ASH_ALIAS
3123 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3124# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003125};
3126
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003127# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003128
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003129#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003130
Eric Andersen2870d962001-07-02 17:27:21 +00003131
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003132/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003133
Denis Vlasenko131ae172007-02-18 13:00:19 +00003134#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003135
3136#define ALIASINUSE 1
3137#define ALIASDEAD 2
3138
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003139struct alias {
3140 struct alias *next;
3141 char *name;
3142 char *val;
3143 int flag;
3144};
3145
Denis Vlasenko01631112007-12-16 17:20:38 +00003146
3147static struct alias **atab; // [ATABSIZE];
3148#define INIT_G_alias() do { \
3149 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3150} while (0)
3151
Eric Andersen2870d962001-07-02 17:27:21 +00003152
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003153static struct alias **
3154__lookupalias(const char *name) {
3155 unsigned int hashval;
3156 struct alias **app;
3157 const char *p;
3158 unsigned int ch;
3159
3160 p = name;
3161
3162 ch = (unsigned char)*p;
3163 hashval = ch << 4;
3164 while (ch) {
3165 hashval += ch;
3166 ch = (unsigned char)*++p;
3167 }
3168 app = &atab[hashval % ATABSIZE];
3169
3170 for (; *app; app = &(*app)->next) {
3171 if (strcmp(name, (*app)->name) == 0) {
3172 break;
3173 }
3174 }
3175
3176 return app;
3177}
3178
3179static struct alias *
3180lookupalias(const char *name, int check)
3181{
3182 struct alias *ap = *__lookupalias(name);
3183
3184 if (check && ap && (ap->flag & ALIASINUSE))
3185 return NULL;
3186 return ap;
3187}
3188
3189static struct alias *
3190freealias(struct alias *ap)
3191{
3192 struct alias *next;
3193
3194 if (ap->flag & ALIASINUSE) {
3195 ap->flag |= ALIASDEAD;
3196 return ap;
3197 }
3198
3199 next = ap->next;
3200 free(ap->name);
3201 free(ap->val);
3202 free(ap);
3203 return next;
3204}
Eric Andersencb57d552001-06-28 07:25:16 +00003205
Eric Andersenc470f442003-07-28 09:56:35 +00003206static void
3207setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003208{
3209 struct alias *ap, **app;
3210
3211 app = __lookupalias(name);
3212 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003213 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003214 if (ap) {
3215 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003216 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003217 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003218 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003219 ap->flag &= ~ALIASDEAD;
3220 } else {
3221 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003222 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003223 ap->name = ckstrdup(name);
3224 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003225 /*ap->flag = 0; - ckzalloc did it */
3226 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003227 *app = ap;
3228 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003229 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003230}
3231
Eric Andersenc470f442003-07-28 09:56:35 +00003232static int
3233unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003234{
Eric Andersencb57d552001-06-28 07:25:16 +00003235 struct alias **app;
3236
3237 app = __lookupalias(name);
3238
3239 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003240 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003241 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003242 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003243 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003244 }
3245
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003246 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003247}
3248
Eric Andersenc470f442003-07-28 09:56:35 +00003249static void
3250rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003251{
Eric Andersencb57d552001-06-28 07:25:16 +00003252 struct alias *ap, **app;
3253 int i;
3254
Denis Vlasenkob012b102007-02-19 22:43:01 +00003255 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003256 for (i = 0; i < ATABSIZE; i++) {
3257 app = &atab[i];
3258 for (ap = *app; ap; ap = *app) {
3259 *app = freealias(*app);
3260 if (ap == *app) {
3261 app = &ap->next;
3262 }
3263 }
3264 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003265 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003266}
3267
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003268static void
3269printalias(const struct alias *ap)
3270{
3271 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3272}
3273
Eric Andersencb57d552001-06-28 07:25:16 +00003274/*
3275 * TODO - sort output
3276 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003277static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003278aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003279{
3280 char *n, *v;
3281 int ret = 0;
3282 struct alias *ap;
3283
Denis Vlasenko68404f12008-03-17 09:00:54 +00003284 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003285 int i;
3286
Denis Vlasenko68404f12008-03-17 09:00:54 +00003287 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003288 for (ap = atab[i]; ap; ap = ap->next) {
3289 printalias(ap);
3290 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003291 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003292 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003293 }
3294 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003295 v = strchr(n+1, '=');
3296 if (v == NULL) { /* n+1: funny ksh stuff */
3297 ap = *__lookupalias(n);
3298 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003299 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003300 ret = 1;
3301 } else
3302 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003303 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003304 *v++ = '\0';
3305 setalias(n, v);
3306 }
3307 }
3308
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003309 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003310}
3311
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003312static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003313unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003314{
3315 int i;
3316
3317 while ((i = nextopt("a")) != '\0') {
3318 if (i == 'a') {
3319 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003320 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003321 }
3322 }
3323 for (i = 0; *argptr; argptr++) {
3324 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003325 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003326 i = 1;
3327 }
3328 }
3329
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003330 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003331}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003332
Denis Vlasenko131ae172007-02-18 13:00:19 +00003333#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003334
Eric Andersenc470f442003-07-28 09:56:35 +00003335
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003336/* ============ jobs.c */
3337
3338/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003339#define FORK_FG 0
3340#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003341#define FORK_NOJOB 2
3342
3343/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003344#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3345#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3346#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003347#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003348
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003349/*
3350 * A job structure contains information about a job. A job is either a
3351 * single process or a set of processes contained in a pipeline. In the
3352 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3353 * array of pids.
3354 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003355struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003356 pid_t ps_pid; /* process id */
3357 int ps_status; /* last process status from wait() */
3358 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003359};
3360
3361struct job {
3362 struct procstat ps0; /* status of process */
3363 struct procstat *ps; /* status or processes when more than one */
3364#if JOBS
3365 int stopstatus; /* status of a stopped job */
3366#endif
3367 uint32_t
3368 nprocs: 16, /* number of processes */
3369 state: 8,
3370#define JOBRUNNING 0 /* at least one proc running */
3371#define JOBSTOPPED 1 /* all procs are stopped */
3372#define JOBDONE 2 /* all procs are completed */
3373#if JOBS
3374 sigint: 1, /* job was killed by SIGINT */
3375 jobctl: 1, /* job running under job control */
3376#endif
3377 waited: 1, /* true if this entry has been waited for */
3378 used: 1, /* true if this entry is in used */
3379 changed: 1; /* true if status has changed */
3380 struct job *prev_job; /* previous job */
3381};
3382
Denis Vlasenko68404f12008-03-17 09:00:54 +00003383static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003384static int forkshell(struct job *, union node *, int);
3385static int waitforjob(struct job *);
3386
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003387#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003388enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003389#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003390#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003391static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003392static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003393#endif
3394
3395/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003396 * Ignore a signal.
3397 */
3398static void
3399ignoresig(int signo)
3400{
3401 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3402 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3403 /* No, need to do it */
3404 signal(signo, SIG_IGN);
3405 }
3406 sigmode[signo - 1] = S_HARD_IGN;
3407}
3408
3409/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003410 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003411 */
3412static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003413signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003414{
3415 gotsig[signo - 1] = 1;
3416
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003417 if (signo == SIGINT && !trap[SIGINT]) {
3418 if (!suppress_int) {
3419 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003420 raise_interrupt(); /* does not return */
3421 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003422 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003423 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003424 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003425 }
3426}
3427
3428/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003429 * Set the signal handler for the specified signal. The routine figures
3430 * out what it should be set to.
3431 */
3432static void
3433setsignal(int signo)
3434{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003435 char *t;
3436 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003437 struct sigaction act;
3438
3439 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003440 new_act = S_DFL;
3441 if (t != NULL) { /* trap for this sig is set */
3442 new_act = S_CATCH;
3443 if (t[0] == '\0') /* trap is "": ignore this sig */
3444 new_act = S_IGN;
3445 }
3446
3447 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003448 switch (signo) {
3449 case SIGINT:
3450 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003451 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003452 break;
3453 case SIGQUIT:
3454#if DEBUG
3455 if (debug)
3456 break;
3457#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003458 /* man bash:
3459 * "In all cases, bash ignores SIGQUIT. Non-builtin
3460 * commands run by bash have signal handlers
3461 * set to the values inherited by the shell
3462 * from its parent". */
3463 new_act = S_IGN;
3464 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003465 case SIGTERM:
3466 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003467 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003468 break;
3469#if JOBS
3470 case SIGTSTP:
3471 case SIGTTOU:
3472 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003473 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003474 break;
3475#endif
3476 }
3477 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003478//TODO: if !rootshell, we reset SIGQUIT to DFL,
3479//whereas we have to restore it to what shell got on entry
3480//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003481
3482 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003483 cur_act = *t;
3484 if (cur_act == 0) {
3485 /* current setting is not yet known */
3486 if (sigaction(signo, NULL, &act)) {
3487 /* pretend it worked; maybe we should give a warning,
3488 * but other shells don't. We don't alter sigmode,
3489 * so we retry every time.
3490 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003491 return;
3492 }
3493 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003494 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003495 if (mflag
3496 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3497 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003498 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003499 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003500 }
3501 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003502 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003503 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003504
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003505 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003506 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003507 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003508 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003509 break;
3510 case S_IGN:
3511 act.sa_handler = SIG_IGN;
3512 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003513 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003514
3515 /* flags and mask matter only if !DFL and !IGN, but we do it
3516 * for all cases for more deterministic behavior:
3517 */
3518 act.sa_flags = 0;
3519 sigfillset(&act.sa_mask);
3520
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003521 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003522
3523 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003524}
3525
3526/* mode flags for set_curjob */
3527#define CUR_DELETE 2
3528#define CUR_RUNNING 1
3529#define CUR_STOPPED 0
3530
3531/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003532#define DOWAIT_NONBLOCK WNOHANG
3533#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003534
3535#if JOBS
3536/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003537static int initialpgrp; //references:2
3538static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539#endif
3540/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003541static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003542/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003543static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003544/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003545static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003546/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003547static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003548
3549static void
3550set_curjob(struct job *jp, unsigned mode)
3551{
3552 struct job *jp1;
3553 struct job **jpp, **curp;
3554
3555 /* first remove from list */
3556 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003557 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003558 jp1 = *jpp;
3559 if (jp1 == jp)
3560 break;
3561 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003562 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003563 *jpp = jp1->prev_job;
3564
3565 /* Then re-insert in correct position */
3566 jpp = curp;
3567 switch (mode) {
3568 default:
3569#if DEBUG
3570 abort();
3571#endif
3572 case CUR_DELETE:
3573 /* job being deleted */
3574 break;
3575 case CUR_RUNNING:
3576 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003577 * put after all stopped jobs.
3578 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003579 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003580 jp1 = *jpp;
3581#if JOBS
3582 if (!jp1 || jp1->state != JOBSTOPPED)
3583#endif
3584 break;
3585 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003586 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003587 /* FALLTHROUGH */
3588#if JOBS
3589 case CUR_STOPPED:
3590#endif
3591 /* newly stopped job - becomes curjob */
3592 jp->prev_job = *jpp;
3593 *jpp = jp;
3594 break;
3595 }
3596}
3597
3598#if JOBS || DEBUG
3599static int
3600jobno(const struct job *jp)
3601{
3602 return jp - jobtab + 1;
3603}
3604#endif
3605
3606/*
3607 * Convert a job name to a job structure.
3608 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003609#if !JOBS
3610#define getjob(name, getctl) getjob(name)
3611#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003612static struct job *
3613getjob(const char *name, int getctl)
3614{
3615 struct job *jp;
3616 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003617 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003618 unsigned num;
3619 int c;
3620 const char *p;
3621 char *(*match)(const char *, const char *);
3622
3623 jp = curjob;
3624 p = name;
3625 if (!p)
3626 goto currentjob;
3627
3628 if (*p != '%')
3629 goto err;
3630
3631 c = *++p;
3632 if (!c)
3633 goto currentjob;
3634
3635 if (!p[1]) {
3636 if (c == '+' || c == '%') {
3637 currentjob:
3638 err_msg = "No current job";
3639 goto check;
3640 }
3641 if (c == '-') {
3642 if (jp)
3643 jp = jp->prev_job;
3644 err_msg = "No previous job";
3645 check:
3646 if (!jp)
3647 goto err;
3648 goto gotit;
3649 }
3650 }
3651
3652 if (is_number(p)) {
3653 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003654 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003655 jp = jobtab + num - 1;
3656 if (jp->used)
3657 goto gotit;
3658 goto err;
3659 }
3660 }
3661
3662 match = prefix;
3663 if (*p == '?') {
3664 match = strstr;
3665 p++;
3666 }
3667
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003668 found = NULL;
3669 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003670 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003671 if (found)
3672 goto err;
3673 found = jp;
3674 err_msg = "%s: ambiguous";
3675 }
3676 jp = jp->prev_job;
3677 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003678 if (!found)
3679 goto err;
3680 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003681
3682 gotit:
3683#if JOBS
3684 err_msg = "job %s not created under job control";
3685 if (getctl && jp->jobctl == 0)
3686 goto err;
3687#endif
3688 return jp;
3689 err:
3690 ash_msg_and_raise_error(err_msg, name);
3691}
3692
3693/*
3694 * Mark a job structure as unused.
3695 */
3696static void
3697freejob(struct job *jp)
3698{
3699 struct procstat *ps;
3700 int i;
3701
3702 INT_OFF;
3703 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003704 if (ps->ps_cmd != nullstr)
3705 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003706 }
3707 if (jp->ps != &jp->ps0)
3708 free(jp->ps);
3709 jp->used = 0;
3710 set_curjob(jp, CUR_DELETE);
3711 INT_ON;
3712}
3713
3714#if JOBS
3715static void
3716xtcsetpgrp(int fd, pid_t pgrp)
3717{
3718 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003719 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003720}
3721
3722/*
3723 * Turn job control on and off.
3724 *
3725 * Note: This code assumes that the third arg to ioctl is a character
3726 * pointer, which is true on Berkeley systems but not System V. Since
3727 * System V doesn't have job control yet, this isn't a problem now.
3728 *
3729 * Called with interrupts off.
3730 */
3731static void
3732setjobctl(int on)
3733{
3734 int fd;
3735 int pgrp;
3736
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003737 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003738 return;
3739 if (on) {
3740 int ofd;
3741 ofd = fd = open(_PATH_TTY, O_RDWR);
3742 if (fd < 0) {
3743 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3744 * That sometimes helps to acquire controlling tty.
3745 * Obviously, a workaround for bugs when someone
3746 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003747 fd = 2;
3748 while (!isatty(fd))
3749 if (--fd < 0)
3750 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003751 }
3752 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003753 if (ofd >= 0)
3754 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003755 if (fd < 0)
3756 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003757 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003758 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003759 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003760 pgrp = tcgetpgrp(fd);
3761 if (pgrp < 0) {
3762 out:
3763 ash_msg("can't access tty; job control turned off");
3764 mflag = on = 0;
3765 goto close;
3766 }
3767 if (pgrp == getpgrp())
3768 break;
3769 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003770 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003771 initialpgrp = pgrp;
3772
3773 setsignal(SIGTSTP);
3774 setsignal(SIGTTOU);
3775 setsignal(SIGTTIN);
3776 pgrp = rootpid;
3777 setpgid(0, pgrp);
3778 xtcsetpgrp(fd, pgrp);
3779 } else {
3780 /* turning job control off */
3781 fd = ttyfd;
3782 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003783 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003784 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003785 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003786 setpgid(0, pgrp);
3787 setsignal(SIGTSTP);
3788 setsignal(SIGTTOU);
3789 setsignal(SIGTTIN);
3790 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003791 if (fd >= 0)
3792 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003793 fd = -1;
3794 }
3795 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003796 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003797}
3798
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003799static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003800killcmd(int argc, char **argv)
3801{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003802 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003803 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003804 do {
3805 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003806 /*
3807 * "kill %N" - job kill
3808 * Converting to pgrp / pid kill
3809 */
3810 struct job *jp;
3811 char *dst;
3812 int j, n;
3813
3814 jp = getjob(argv[i], 0);
3815 /*
3816 * In jobs started under job control, we signal
3817 * entire process group by kill -PGRP_ID.
3818 * This happens, f.e., in interactive shell.
3819 *
3820 * Otherwise, we signal each child via
3821 * kill PID1 PID2 PID3.
3822 * Testcases:
3823 * sh -c 'sleep 1|sleep 1 & kill %1'
3824 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3825 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3826 */
3827 n = jp->nprocs; /* can't be 0 (I hope) */
3828 if (jp->jobctl)
3829 n = 1;
3830 dst = alloca(n * sizeof(int)*4);
3831 argv[i] = dst;
3832 for (j = 0; j < n; j++) {
3833 struct procstat *ps = &jp->ps[j];
3834 /* Skip non-running and not-stopped members
3835 * (i.e. dead members) of the job
3836 */
3837 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3838 continue;
3839 /*
3840 * kill_main has matching code to expect
3841 * leading space. Needed to not confuse
3842 * negative pids with "kill -SIGNAL_NO" syntax
3843 */
3844 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3845 }
3846 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003847 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003848 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003849 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003850 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003851}
3852
3853static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003854showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003855{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003856 struct procstat *ps;
3857 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003858
Denys Vlasenko285ad152009-12-04 23:02:27 +01003859 psend = jp->ps + jp->nprocs;
3860 for (ps = jp->ps + 1; ps < psend; ps++)
3861 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003862 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003863 flush_stdout_stderr();
3864}
3865
3866
3867static int
3868restartjob(struct job *jp, int mode)
3869{
3870 struct procstat *ps;
3871 int i;
3872 int status;
3873 pid_t pgid;
3874
3875 INT_OFF;
3876 if (jp->state == JOBDONE)
3877 goto out;
3878 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003879 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003880 if (mode == FORK_FG)
3881 xtcsetpgrp(ttyfd, pgid);
3882 killpg(pgid, SIGCONT);
3883 ps = jp->ps;
3884 i = jp->nprocs;
3885 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003886 if (WIFSTOPPED(ps->ps_status)) {
3887 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003888 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003889 ps++;
3890 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003891 out:
3892 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3893 INT_ON;
3894 return status;
3895}
3896
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003897static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003898fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003899{
3900 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003901 int mode;
3902 int retval;
3903
3904 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3905 nextopt(nullstr);
3906 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003907 do {
3908 jp = getjob(*argv, 1);
3909 if (mode == FORK_BG) {
3910 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003911 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003912 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003913 out1str(jp->ps[0].ps_cmd);
3914 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003915 retval = restartjob(jp, mode);
3916 } while (*argv && *++argv);
3917 return retval;
3918}
3919#endif
3920
3921static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003922sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003923{
3924 int col;
3925 int st;
3926
3927 col = 0;
3928 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003929 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003930 st = WSTOPSIG(status);
3931 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003932 st = WTERMSIG(status);
3933 if (sigonly) {
3934 if (st == SIGINT || st == SIGPIPE)
3935 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003936 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003937 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003938 }
3939 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003940//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003941 col = fmtstr(s, 32, strsignal(st));
3942 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003943 strcpy(s + col, " (core dumped)");
3944 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003945 }
3946 } else if (!sigonly) {
3947 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003948 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003949 }
3950 out:
3951 return col;
3952}
3953
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003954static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003955dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003956{
3957 int pid;
3958 int status;
3959 struct job *jp;
3960 struct job *thisjob;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003961
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003962 TRACE(("dowait(0x%x) called\n", wait_flags));
3963
3964 /* Do a wait system call. If job control is compiled in, we accept
3965 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3966 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003967 if (doing_jobctl)
3968 wait_flags |= WUNTRACED;
3969 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003970 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3971 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003972 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003973 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003974
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003975 INT_OFF;
3976 thisjob = NULL;
3977 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003978 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003979 struct procstat *ps;
3980 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981 if (jp->state == JOBDONE)
3982 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003983 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003984 ps = jp->ps;
3985 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003986 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003987 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003988 TRACE(("Job %d: changing status of proc %d "
3989 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003990 jobno(jp), pid, ps->ps_status, status));
3991 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003992 thisjob = jp;
3993 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003994 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003995 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003996#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003997 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003998 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003999 if (WIFSTOPPED(ps->ps_status)) {
4000 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004001 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004002 }
4003#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004004 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004005 if (!thisjob)
4006 continue;
4007
4008 /* Found the job where one of its processes changed its state.
4009 * Is there at least one live and running process in this job? */
4010 if (jobstate != JOBRUNNING) {
4011 /* No. All live processes in the job are stopped
4012 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4013 */
4014 thisjob->changed = 1;
4015 if (thisjob->state != jobstate) {
4016 TRACE(("Job %d: changing state from %d to %d\n",
4017 jobno(thisjob), thisjob->state, jobstate));
4018 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004019#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004020 if (jobstate == JOBSTOPPED)
4021 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004022#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004023 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004024 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004025 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004026 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004027 /* The process wasn't found in job list */
4028 if (JOBS && !WIFSTOPPED(status))
4029 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004030 out:
4031 INT_ON;
4032
4033 if (thisjob && thisjob == job) {
4034 char s[48 + 1];
4035 int len;
4036
Denys Vlasenko9c541002015-10-07 15:44:36 +02004037 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004038 if (len) {
4039 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004040 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004041 out2str(s);
4042 }
4043 }
4044 return pid;
4045}
4046
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004047static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004048blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004049{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004050 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004051 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004052 raise_exception(EXSIG);
4053 return pid;
4054}
4055
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004056#if JOBS
4057static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004058showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004059{
4060 struct procstat *ps;
4061 struct procstat *psend;
4062 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004063 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004064 char s[16 + 16 + 48];
4065 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004066
4067 ps = jp->ps;
4068
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004069 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004070 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004071 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072 return;
4073 }
4074
4075 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004076 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004077
4078 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004079 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004080 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004081 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004082
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004083 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004084 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004085
4086 psend = ps + jp->nprocs;
4087
4088 if (jp->state == JOBRUNNING) {
4089 strcpy(s + col, "Running");
4090 col += sizeof("Running") - 1;
4091 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004092 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004093 if (jp->state == JOBSTOPPED)
4094 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004095 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004096 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004097 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004098
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004099 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4100 * or prints several "PID | <cmdN>" lines,
4101 * depending on SHOW_PIDS bit.
4102 * We do not print status of individual processes
4103 * between PID and <cmdN>. bash does it, but not very well:
4104 * first line shows overall job status, not process status,
4105 * making it impossible to know 1st process status.
4106 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004107 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004108 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004109 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004110 s[0] = '\0';
4111 col = 33;
4112 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004113 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004114 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004115 fprintf(out, "%s%*c%s%s",
4116 s,
4117 33 - col >= 0 ? 33 - col : 0, ' ',
4118 ps == jp->ps ? "" : "| ",
4119 ps->ps_cmd
4120 );
4121 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004122 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004123
4124 jp->changed = 0;
4125
4126 if (jp->state == JOBDONE) {
4127 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4128 freejob(jp);
4129 }
4130}
4131
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004132/*
4133 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4134 * statuses have changed since the last call to showjobs.
4135 */
4136static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004137showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138{
4139 struct job *jp;
4140
Denys Vlasenko883cea42009-07-11 15:31:59 +02004141 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004142
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004143 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004144 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004145 continue;
4146
4147 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004148 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004149 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004150 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004151 }
4152}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004153
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004154static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004155jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004156{
4157 int mode, m;
4158
4159 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004160 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004161 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004162 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004163 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004164 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004165 }
4166
4167 argv = argptr;
4168 if (*argv) {
4169 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004170 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004171 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004172 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004173 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004174 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004175
4176 return 0;
4177}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004178#endif /* JOBS */
4179
Michael Abbott359da5e2009-12-04 23:03:29 +01004180/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004181static int
4182getstatus(struct job *job)
4183{
4184 int status;
4185 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004186 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004187
Michael Abbott359da5e2009-12-04 23:03:29 +01004188 /* Fetch last member's status */
4189 ps = job->ps + job->nprocs - 1;
4190 status = ps->ps_status;
4191 if (pipefail) {
4192 /* "set -o pipefail" mode: use last _nonzero_ status */
4193 while (status == 0 && --ps >= job->ps)
4194 status = ps->ps_status;
4195 }
4196
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004197 retval = WEXITSTATUS(status);
4198 if (!WIFEXITED(status)) {
4199#if JOBS
4200 retval = WSTOPSIG(status);
4201 if (!WIFSTOPPED(status))
4202#endif
4203 {
4204 /* XXX: limits number of signals */
4205 retval = WTERMSIG(status);
4206#if JOBS
4207 if (retval == SIGINT)
4208 job->sigint = 1;
4209#endif
4210 }
4211 retval += 128;
4212 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004213 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004214 jobno(job), job->nprocs, status, retval));
4215 return retval;
4216}
4217
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004218static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004219waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004220{
4221 struct job *job;
4222 int retval;
4223 struct job *jp;
4224
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004225 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004226 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004227
4228 nextopt(nullstr);
4229 retval = 0;
4230
4231 argv = argptr;
4232 if (!*argv) {
4233 /* wait for all jobs */
4234 for (;;) {
4235 jp = curjob;
4236 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004237 if (!jp) /* no running procs */
4238 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004239 if (jp->state == JOBRUNNING)
4240 break;
4241 jp->waited = 1;
4242 jp = jp->prev_job;
4243 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004244 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004245 /* man bash:
4246 * "When bash is waiting for an asynchronous command via
4247 * the wait builtin, the reception of a signal for which a trap
4248 * has been set will cause the wait builtin to return immediately
4249 * with an exit status greater than 128, immediately after which
4250 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004251 *
4252 * blocking_wait_with_raise_on_sig raises signal handlers
4253 * if it gets no pid (pid < 0). However,
4254 * if child sends us a signal *and immediately exits*,
4255 * blocking_wait_with_raise_on_sig gets pid > 0
4256 * and does not handle pending_sig. Check this case: */
4257 if (pending_sig)
4258 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004259 }
4260 }
4261
4262 retval = 127;
4263 do {
4264 if (**argv != '%') {
4265 pid_t pid = number(*argv);
4266 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004267 while (1) {
4268 if (!job)
4269 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004270 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004271 break;
4272 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004273 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004274 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004275 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004276 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004277 /* loop until process terminated or stopped */
4278 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004279 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004280 job->waited = 1;
4281 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004282 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004283 } while (*++argv);
4284
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004285 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004286 return retval;
4287}
4288
4289static struct job *
4290growjobtab(void)
4291{
4292 size_t len;
4293 ptrdiff_t offset;
4294 struct job *jp, *jq;
4295
4296 len = njobs * sizeof(*jp);
4297 jq = jobtab;
4298 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4299
4300 offset = (char *)jp - (char *)jq;
4301 if (offset) {
4302 /* Relocate pointers */
4303 size_t l = len;
4304
4305 jq = (struct job *)((char *)jq + l);
4306 while (l) {
4307 l -= sizeof(*jp);
4308 jq--;
4309#define joff(p) ((struct job *)((char *)(p) + l))
4310#define jmove(p) (p) = (void *)((char *)(p) + offset)
4311 if (joff(jp)->ps == &jq->ps0)
4312 jmove(joff(jp)->ps);
4313 if (joff(jp)->prev_job)
4314 jmove(joff(jp)->prev_job);
4315 }
4316 if (curjob)
4317 jmove(curjob);
4318#undef joff
4319#undef jmove
4320 }
4321
4322 njobs += 4;
4323 jobtab = jp;
4324 jp = (struct job *)((char *)jp + len);
4325 jq = jp + 3;
4326 do {
4327 jq->used = 0;
4328 } while (--jq >= jp);
4329 return jp;
4330}
4331
4332/*
4333 * Return a new job structure.
4334 * Called with interrupts off.
4335 */
4336static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004337makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004338{
4339 int i;
4340 struct job *jp;
4341
4342 for (i = njobs, jp = jobtab; ; jp++) {
4343 if (--i < 0) {
4344 jp = growjobtab();
4345 break;
4346 }
4347 if (jp->used == 0)
4348 break;
4349 if (jp->state != JOBDONE || !jp->waited)
4350 continue;
4351#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004352 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004353 continue;
4354#endif
4355 freejob(jp);
4356 break;
4357 }
4358 memset(jp, 0, sizeof(*jp));
4359#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004360 /* jp->jobctl is a bitfield.
4361 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004362 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004363 jp->jobctl = 1;
4364#endif
4365 jp->prev_job = curjob;
4366 curjob = jp;
4367 jp->used = 1;
4368 jp->ps = &jp->ps0;
4369 if (nprocs > 1) {
4370 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4371 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004372 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004373 jobno(jp)));
4374 return jp;
4375}
4376
4377#if JOBS
4378/*
4379 * Return a string identifying a command (to be printed by the
4380 * jobs command).
4381 */
4382static char *cmdnextc;
4383
4384static void
4385cmdputs(const char *s)
4386{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004387 static const char vstype[VSTYPE + 1][3] = {
4388 "", "}", "-", "+", "?", "=",
4389 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004390 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004391 };
4392
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004393 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004394 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004395 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004396 unsigned char c;
4397 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004398 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004399
Denys Vlasenko46a14772009-12-10 21:27:13 +01004400 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004401 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4402 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004403 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004404 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004405 switch (c) {
4406 case CTLESC:
4407 c = *p++;
4408 break;
4409 case CTLVAR:
4410 subtype = *p++;
4411 if ((subtype & VSTYPE) == VSLENGTH)
4412 str = "${#";
4413 else
4414 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004415 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004416 case CTLENDVAR:
4417 str = "\"}" + !(quoted & 1);
4418 quoted >>= 1;
4419 subtype = 0;
4420 goto dostr;
4421 case CTLBACKQ:
4422 str = "$(...)";
4423 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004424#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004425 case CTLARI:
4426 str = "$((";
4427 goto dostr;
4428 case CTLENDARI:
4429 str = "))";
4430 goto dostr;
4431#endif
4432 case CTLQUOTEMARK:
4433 quoted ^= 1;
4434 c = '"';
4435 break;
4436 case '=':
4437 if (subtype == 0)
4438 break;
4439 if ((subtype & VSTYPE) != VSNORMAL)
4440 quoted <<= 1;
4441 str = vstype[subtype & VSTYPE];
4442 if (subtype & VSNUL)
4443 c = ':';
4444 else
4445 goto checkstr;
4446 break;
4447 case '\'':
4448 case '\\':
4449 case '"':
4450 case '$':
4451 /* These can only happen inside quotes */
4452 cc[0] = c;
4453 str = cc;
4454 c = '\\';
4455 break;
4456 default:
4457 break;
4458 }
4459 USTPUTC(c, nextc);
4460 checkstr:
4461 if (!str)
4462 continue;
4463 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004464 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004465 USTPUTC(c, nextc);
4466 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004467 } /* while *p++ not NUL */
4468
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004469 if (quoted & 1) {
4470 USTPUTC('"', nextc);
4471 }
4472 *nextc = 0;
4473 cmdnextc = nextc;
4474}
4475
4476/* cmdtxt() and cmdlist() call each other */
4477static void cmdtxt(union node *n);
4478
4479static void
4480cmdlist(union node *np, int sep)
4481{
4482 for (; np; np = np->narg.next) {
4483 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004484 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004485 cmdtxt(np);
4486 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004487 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004488 }
4489}
4490
4491static void
4492cmdtxt(union node *n)
4493{
4494 union node *np;
4495 struct nodelist *lp;
4496 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004497
4498 if (!n)
4499 return;
4500 switch (n->type) {
4501 default:
4502#if DEBUG
4503 abort();
4504#endif
4505 case NPIPE:
4506 lp = n->npipe.cmdlist;
4507 for (;;) {
4508 cmdtxt(lp->n);
4509 lp = lp->next;
4510 if (!lp)
4511 break;
4512 cmdputs(" | ");
4513 }
4514 break;
4515 case NSEMI:
4516 p = "; ";
4517 goto binop;
4518 case NAND:
4519 p = " && ";
4520 goto binop;
4521 case NOR:
4522 p = " || ";
4523 binop:
4524 cmdtxt(n->nbinary.ch1);
4525 cmdputs(p);
4526 n = n->nbinary.ch2;
4527 goto donode;
4528 case NREDIR:
4529 case NBACKGND:
4530 n = n->nredir.n;
4531 goto donode;
4532 case NNOT:
4533 cmdputs("!");
4534 n = n->nnot.com;
4535 donode:
4536 cmdtxt(n);
4537 break;
4538 case NIF:
4539 cmdputs("if ");
4540 cmdtxt(n->nif.test);
4541 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004542 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004543 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004544 cmdputs("; else ");
4545 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004546 } else {
4547 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004548 }
4549 p = "; fi";
4550 goto dotail;
4551 case NSUBSHELL:
4552 cmdputs("(");
4553 n = n->nredir.n;
4554 p = ")";
4555 goto dotail;
4556 case NWHILE:
4557 p = "while ";
4558 goto until;
4559 case NUNTIL:
4560 p = "until ";
4561 until:
4562 cmdputs(p);
4563 cmdtxt(n->nbinary.ch1);
4564 n = n->nbinary.ch2;
4565 p = "; done";
4566 dodo:
4567 cmdputs("; do ");
4568 dotail:
4569 cmdtxt(n);
4570 goto dotail2;
4571 case NFOR:
4572 cmdputs("for ");
4573 cmdputs(n->nfor.var);
4574 cmdputs(" in ");
4575 cmdlist(n->nfor.args, 1);
4576 n = n->nfor.body;
4577 p = "; done";
4578 goto dodo;
4579 case NDEFUN:
4580 cmdputs(n->narg.text);
4581 p = "() { ... }";
4582 goto dotail2;
4583 case NCMD:
4584 cmdlist(n->ncmd.args, 1);
4585 cmdlist(n->ncmd.redirect, 0);
4586 break;
4587 case NARG:
4588 p = n->narg.text;
4589 dotail2:
4590 cmdputs(p);
4591 break;
4592 case NHERE:
4593 case NXHERE:
4594 p = "<<...";
4595 goto dotail2;
4596 case NCASE:
4597 cmdputs("case ");
4598 cmdputs(n->ncase.expr->narg.text);
4599 cmdputs(" in ");
4600 for (np = n->ncase.cases; np; np = np->nclist.next) {
4601 cmdtxt(np->nclist.pattern);
4602 cmdputs(") ");
4603 cmdtxt(np->nclist.body);
4604 cmdputs(";; ");
4605 }
4606 p = "esac";
4607 goto dotail2;
4608 case NTO:
4609 p = ">";
4610 goto redir;
4611 case NCLOBBER:
4612 p = ">|";
4613 goto redir;
4614 case NAPPEND:
4615 p = ">>";
4616 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004617#if ENABLE_ASH_BASH_COMPAT
4618 case NTO2:
4619#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004620 case NTOFD:
4621 p = ">&";
4622 goto redir;
4623 case NFROM:
4624 p = "<";
4625 goto redir;
4626 case NFROMFD:
4627 p = "<&";
4628 goto redir;
4629 case NFROMTO:
4630 p = "<>";
4631 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004632 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004633 cmdputs(p);
4634 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004635 cmdputs(utoa(n->ndup.dupfd));
4636 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004637 }
4638 n = n->nfile.fname;
4639 goto donode;
4640 }
4641}
4642
4643static char *
4644commandtext(union node *n)
4645{
4646 char *name;
4647
4648 STARTSTACKSTR(cmdnextc);
4649 cmdtxt(n);
4650 name = stackblock();
4651 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4652 name, cmdnextc, cmdnextc));
4653 return ckstrdup(name);
4654}
4655#endif /* JOBS */
4656
4657/*
4658 * Fork off a subshell. If we are doing job control, give the subshell its
4659 * own process group. Jp is a job structure that the job is to be added to.
4660 * N is the command that will be evaluated by the child. Both jp and n may
4661 * be NULL. The mode parameter can be one of the following:
4662 * FORK_FG - Fork off a foreground process.
4663 * FORK_BG - Fork off a background process.
4664 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4665 * process group even if job control is on.
4666 *
4667 * When job control is turned off, background processes have their standard
4668 * input redirected to /dev/null (except for the second and later processes
4669 * in a pipeline).
4670 *
4671 * Called with interrupts off.
4672 */
4673/*
4674 * Clear traps on a fork.
4675 */
4676static void
4677clear_traps(void)
4678{
4679 char **tp;
4680
4681 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004682 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004683 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004684 if (trap_ptr == trap)
4685 free(*tp);
4686 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004687 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004688 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004689 setsignal(tp - trap);
4690 INT_ON;
4691 }
4692 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004693 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004694}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004695
4696/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004697static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004698
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004699/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004700static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004701forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004702{
4703 int oldlvl;
4704
4705 TRACE(("Child shell %d\n", getpid()));
4706 oldlvl = shlvl;
4707 shlvl++;
4708
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004709 /* man bash: "Non-builtin commands run by bash have signal handlers
4710 * set to the values inherited by the shell from its parent".
4711 * Do we do it correctly? */
4712
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004713 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004714
4715 if (mode == FORK_NOJOB /* is it `xxx` ? */
4716 && n && n->type == NCMD /* is it single cmd? */
4717 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004718 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004719 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4720 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4721 ) {
4722 TRACE(("Trap hack\n"));
4723 /* Awful hack for `trap` or $(trap).
4724 *
4725 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4726 * contains an example where "trap" is executed in a subshell:
4727 *
4728 * save_traps=$(trap)
4729 * ...
4730 * eval "$save_traps"
4731 *
4732 * Standard does not say that "trap" in subshell shall print
4733 * parent shell's traps. It only says that its output
4734 * must have suitable form, but then, in the above example
4735 * (which is not supposed to be normative), it implies that.
4736 *
4737 * bash (and probably other shell) does implement it
4738 * (traps are reset to defaults, but "trap" still shows them),
4739 * but as a result, "trap" logic is hopelessly messed up:
4740 *
4741 * # trap
4742 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4743 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4744 * # true | trap <--- trap is in subshell - no output (ditto)
4745 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4746 * trap -- 'echo Ho' SIGWINCH
4747 * # echo `(trap)` <--- in subshell in subshell - output
4748 * trap -- 'echo Ho' SIGWINCH
4749 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4750 * trap -- 'echo Ho' SIGWINCH
4751 *
4752 * The rules when to forget and when to not forget traps
4753 * get really complex and nonsensical.
4754 *
4755 * Our solution: ONLY bare $(trap) or `trap` is special.
4756 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004757 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004758 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004759 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004760 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004761 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004762#if JOBS
4763 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004764 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004765 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004766 pid_t pgrp;
4767
4768 if (jp->nprocs == 0)
4769 pgrp = getpid();
4770 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004771 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004772 /* this can fail because we are doing it in the parent also */
4773 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004774 if (mode == FORK_FG)
4775 xtcsetpgrp(ttyfd, pgrp);
4776 setsignal(SIGTSTP);
4777 setsignal(SIGTTOU);
4778 } else
4779#endif
4780 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004781 /* man bash: "When job control is not in effect,
4782 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004783 ignoresig(SIGINT);
4784 ignoresig(SIGQUIT);
4785 if (jp->nprocs == 0) {
4786 close(0);
4787 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004788 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004789 }
4790 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004791 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004792 if (iflag) { /* why if iflag only? */
4793 setsignal(SIGINT);
4794 setsignal(SIGTERM);
4795 }
4796 /* man bash:
4797 * "In all cases, bash ignores SIGQUIT. Non-builtin
4798 * commands run by bash have signal handlers
4799 * set to the values inherited by the shell
4800 * from its parent".
4801 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004802 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004803 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004804#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004805 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004806 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004807 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004808 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004809 /* "jobs": we do not want to clear job list for it,
4810 * instead we remove only _its_ own_ job from job list.
4811 * This makes "jobs .... | cat" more useful.
4812 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004813 freejob(curjob);
4814 return;
4815 }
4816#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004817 for (jp = curjob; jp; jp = jp->prev_job)
4818 freejob(jp);
4819 jobless = 0;
4820}
4821
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004822/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004823#if !JOBS
4824#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4825#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004826static void
4827forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4828{
4829 TRACE(("In parent shell: child = %d\n", pid));
4830 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004831 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4832 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004833 jobless++;
4834 return;
4835 }
4836#if JOBS
4837 if (mode != FORK_NOJOB && jp->jobctl) {
4838 int pgrp;
4839
4840 if (jp->nprocs == 0)
4841 pgrp = pid;
4842 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004843 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004844 /* This can fail because we are doing it in the child also */
4845 setpgid(pid, pgrp);
4846 }
4847#endif
4848 if (mode == FORK_BG) {
4849 backgndpid = pid; /* set $! */
4850 set_curjob(jp, CUR_RUNNING);
4851 }
4852 if (jp) {
4853 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004854 ps->ps_pid = pid;
4855 ps->ps_status = -1;
4856 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004857#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004858 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004859 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004860#endif
4861 }
4862}
4863
4864static int
4865forkshell(struct job *jp, union node *n, int mode)
4866{
4867 int pid;
4868
4869 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4870 pid = fork();
4871 if (pid < 0) {
4872 TRACE(("Fork failed, errno=%d", errno));
4873 if (jp)
4874 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004875 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004876 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004877 if (pid == 0) {
4878 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004879 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004880 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004881 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004882 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004883 return pid;
4884}
4885
4886/*
4887 * Wait for job to finish.
4888 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004889 * Under job control we have the problem that while a child process
4890 * is running interrupts generated by the user are sent to the child
4891 * but not to the shell. This means that an infinite loop started by
4892 * an interactive user may be hard to kill. With job control turned off,
4893 * an interactive user may place an interactive program inside a loop.
4894 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004895 * these interrupts to also abort the loop. The approach we take here
4896 * is to have the shell ignore interrupt signals while waiting for a
4897 * foreground process to terminate, and then send itself an interrupt
4898 * signal if the child process was terminated by an interrupt signal.
4899 * Unfortunately, some programs want to do a bit of cleanup and then
4900 * exit on interrupt; unless these processes terminate themselves by
4901 * sending a signal to themselves (instead of calling exit) they will
4902 * confuse this approach.
4903 *
4904 * Called with interrupts off.
4905 */
4906static int
4907waitforjob(struct job *jp)
4908{
4909 int st;
4910
4911 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004912
4913 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004914 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004915 /* In non-interactive shells, we _can_ get
4916 * a keyboard signal here and be EINTRed,
4917 * but we just loop back, waiting for command to complete.
4918 *
4919 * man bash:
4920 * "If bash is waiting for a command to complete and receives
4921 * a signal for which a trap has been set, the trap
4922 * will not be executed until the command completes."
4923 *
4924 * Reality is that even if trap is not set, bash
4925 * will not act on the signal until command completes.
4926 * Try this. sleep5intoff.c:
4927 * #include <signal.h>
4928 * #include <unistd.h>
4929 * int main() {
4930 * sigset_t set;
4931 * sigemptyset(&set);
4932 * sigaddset(&set, SIGINT);
4933 * sigaddset(&set, SIGQUIT);
4934 * sigprocmask(SIG_BLOCK, &set, NULL);
4935 * sleep(5);
4936 * return 0;
4937 * }
4938 * $ bash -c './sleep5intoff; echo hi'
4939 * ^C^C^C^C <--- pressing ^C once a second
4940 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004941 * $ bash -c './sleep5intoff; echo hi'
4942 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4943 * $ _
4944 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004945 dowait(DOWAIT_BLOCK, jp);
4946 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004947 INT_ON;
4948
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004949 st = getstatus(jp);
4950#if JOBS
4951 if (jp->jobctl) {
4952 xtcsetpgrp(ttyfd, rootpid);
4953 /*
4954 * This is truly gross.
4955 * If we're doing job control, then we did a TIOCSPGRP which
4956 * caused us (the shell) to no longer be in the controlling
4957 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4958 * intuit from the subprocess exit status whether a SIGINT
4959 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4960 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004961 if (jp->sigint) /* TODO: do the same with all signals */
4962 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004963 }
4964 if (jp->state == JOBDONE)
4965#endif
4966 freejob(jp);
4967 return st;
4968}
4969
4970/*
4971 * return 1 if there are stopped jobs, otherwise 0
4972 */
4973static int
4974stoppedjobs(void)
4975{
4976 struct job *jp;
4977 int retval;
4978
4979 retval = 0;
4980 if (job_warning)
4981 goto out;
4982 jp = curjob;
4983 if (jp && jp->state == JOBSTOPPED) {
4984 out2str("You have stopped jobs.\n");
4985 job_warning = 2;
4986 retval++;
4987 }
4988 out:
4989 return retval;
4990}
4991
4992
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004993/* ============ redir.c
4994 *
4995 * Code for dealing with input/output redirection.
4996 */
4997
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01004998#undef EMPTY
4999#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005000#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005001#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005002
5003/*
5004 * Open a file in noclobber mode.
5005 * The code was copied from bash.
5006 */
5007static int
5008noclobberopen(const char *fname)
5009{
5010 int r, fd;
5011 struct stat finfo, finfo2;
5012
5013 /*
5014 * If the file exists and is a regular file, return an error
5015 * immediately.
5016 */
5017 r = stat(fname, &finfo);
5018 if (r == 0 && S_ISREG(finfo.st_mode)) {
5019 errno = EEXIST;
5020 return -1;
5021 }
5022
5023 /*
5024 * If the file was not present (r != 0), make sure we open it
5025 * exclusively so that if it is created before we open it, our open
5026 * will fail. Make sure that we do not truncate an existing file.
5027 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5028 * file was not a regular file, we leave O_EXCL off.
5029 */
5030 if (r != 0)
5031 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5032 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5033
5034 /* If the open failed, return the file descriptor right away. */
5035 if (fd < 0)
5036 return fd;
5037
5038 /*
5039 * OK, the open succeeded, but the file may have been changed from a
5040 * non-regular file to a regular file between the stat and the open.
5041 * We are assuming that the O_EXCL open handles the case where FILENAME
5042 * did not exist and is symlinked to an existing file between the stat
5043 * and open.
5044 */
5045
5046 /*
5047 * If we can open it and fstat the file descriptor, and neither check
5048 * revealed that it was a regular file, and the file has not been
5049 * replaced, return the file descriptor.
5050 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005051 if (fstat(fd, &finfo2) == 0
5052 && !S_ISREG(finfo2.st_mode)
5053 && finfo.st_dev == finfo2.st_dev
5054 && finfo.st_ino == finfo2.st_ino
5055 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005056 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005057 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005058
5059 /* The file has been replaced. badness. */
5060 close(fd);
5061 errno = EEXIST;
5062 return -1;
5063}
5064
5065/*
5066 * Handle here documents. Normally we fork off a process to write the
5067 * data to a pipe. If the document is short, we can stuff the data in
5068 * the pipe without forking.
5069 */
5070/* openhere needs this forward reference */
5071static void expandhere(union node *arg, int fd);
5072static int
5073openhere(union node *redir)
5074{
5075 int pip[2];
5076 size_t len = 0;
5077
5078 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005079 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005080 if (redir->type == NHERE) {
5081 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005082 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005083 full_write(pip[1], redir->nhere.doc->narg.text, len);
5084 goto out;
5085 }
5086 }
5087 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005088 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005089 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005090 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5091 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5092 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5093 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005094 signal(SIGPIPE, SIG_DFL);
5095 if (redir->type == NHERE)
5096 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005097 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005098 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005099 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005100 }
5101 out:
5102 close(pip[1]);
5103 return pip[0];
5104}
5105
5106static int
5107openredirect(union node *redir)
5108{
5109 char *fname;
5110 int f;
5111
5112 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005113/* Can't happen, our single caller does this itself */
5114// case NTOFD:
5115// case NFROMFD:
5116// return -1;
5117 case NHERE:
5118 case NXHERE:
5119 return openhere(redir);
5120 }
5121
5122 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5123 * allocated space. Do it only when we know it is safe.
5124 */
5125 fname = redir->nfile.expfname;
5126
5127 switch (redir->nfile.type) {
5128 default:
5129#if DEBUG
5130 abort();
5131#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005132 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005133 f = open(fname, O_RDONLY);
5134 if (f < 0)
5135 goto eopen;
5136 break;
5137 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005138 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005139 if (f < 0)
5140 goto ecreate;
5141 break;
5142 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005143#if ENABLE_ASH_BASH_COMPAT
5144 case NTO2:
5145#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005146 /* Take care of noclobber mode. */
5147 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005148 f = noclobberopen(fname);
5149 if (f < 0)
5150 goto ecreate;
5151 break;
5152 }
5153 /* FALLTHROUGH */
5154 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005155 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5156 if (f < 0)
5157 goto ecreate;
5158 break;
5159 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005160 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5161 if (f < 0)
5162 goto ecreate;
5163 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005164 }
5165
5166 return f;
5167 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005168 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005169 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005170 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005171}
5172
5173/*
5174 * Copy a file descriptor to be >= to. Returns -1
5175 * if the source file descriptor is closed, EMPTY if there are no unused
5176 * file descriptors left.
5177 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005178/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5179 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005180enum {
5181 COPYFD_EXACT = (int)~(INT_MAX),
5182 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5183};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005184static int
5185copyfd(int from, int to)
5186{
5187 int newfd;
5188
Denis Vlasenko5a867312008-07-24 19:46:38 +00005189 if (to & COPYFD_EXACT) {
5190 to &= ~COPYFD_EXACT;
5191 /*if (from != to)*/
5192 newfd = dup2(from, to);
5193 } else {
5194 newfd = fcntl(from, F_DUPFD, to);
5195 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005196 if (newfd < 0) {
5197 if (errno == EMFILE)
5198 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005199 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005200 ash_msg_and_raise_error("%d: %m", from);
5201 }
5202 return newfd;
5203}
5204
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005205/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005206struct two_fd_t {
5207 int orig, copy;
5208};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005209struct redirtab {
5210 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005211 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005212 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005213 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005214};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005215#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005216
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005217static int need_to_remember(struct redirtab *rp, int fd)
5218{
5219 int i;
5220
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005221 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005222 return 0;
5223
5224 for (i = 0; i < rp->pair_count; i++) {
5225 if (rp->two_fd[i].orig == fd) {
5226 /* already remembered */
5227 return 0;
5228 }
5229 }
5230 return 1;
5231}
5232
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005233/* "hidden" fd is a fd used to read scripts, or a copy of such */
5234static int is_hidden_fd(struct redirtab *rp, int fd)
5235{
5236 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005237 struct parsefile *pf;
5238
5239 if (fd == -1)
5240 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005241 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005242 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005243 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005244 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005245 * $ ash # running ash interactively
5246 * $ . ./script.sh
5247 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005248 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005249 * it's still ok to use it: "read" builtin uses it,
5250 * why should we cripple "exec" builtin?
5251 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005252 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005253 return 1;
5254 }
5255 pf = pf->prev;
5256 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005257
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005258 if (!rp)
5259 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005260 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005261 fd |= COPYFD_RESTORE;
5262 for (i = 0; i < rp->pair_count; i++) {
5263 if (rp->two_fd[i].copy == fd) {
5264 return 1;
5265 }
5266 }
5267 return 0;
5268}
5269
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005270/*
5271 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5272 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005273 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005274 */
5275/* flags passed to redirect */
5276#define REDIR_PUSH 01 /* save previous values of file descriptors */
5277#define REDIR_SAVEFD2 03 /* set preverrout */
5278static void
5279redirect(union node *redir, int flags)
5280{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005281 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005282 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005283 int i;
5284 int fd;
5285 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005286 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005287
Denis Vlasenko01631112007-12-16 17:20:38 +00005288 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005289 if (!redir) {
5290 return;
5291 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005292
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005293 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005294 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005295 INT_OFF;
5296 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005297 union node *tmp = redir;
5298 do {
5299 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005300#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005301 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005302 sv_pos++;
5303#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005304 tmp = tmp->nfile.next;
5305 } while (tmp);
5306 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005307 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005308 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005309 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005310 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005311 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005312 while (sv_pos > 0) {
5313 sv_pos--;
5314 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5315 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005316 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005317
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005318 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005319 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005320 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005321 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005322 right_fd = redir->ndup.dupfd;
5323 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005324 /* redirect from/to same file descriptor? */
5325 if (right_fd == fd)
5326 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005327 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005328 if (is_hidden_fd(sv, right_fd)) {
5329 errno = EBADF; /* as if it is closed */
5330 ash_msg_and_raise_error("%d: %m", right_fd);
5331 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005332 newfd = -1;
5333 } else {
5334 newfd = openredirect(redir); /* always >= 0 */
5335 if (fd == newfd) {
5336 /* Descriptor wasn't open before redirect.
5337 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005338 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005339 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005340 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005341 continue;
5342 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005343 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005344#if ENABLE_ASH_BASH_COMPAT
5345 redirect_more:
5346#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005347 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005348 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005349 /* Careful to not accidentally "save"
5350 * to the same fd as right side fd in N>&M */
5351 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5352 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005353/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5354 * are closed in popredir() in the child, preventing them from leaking
5355 * into child. (popredir() also cleans up the mess in case of failures)
5356 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005357 if (i == -1) {
5358 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005359 if (i != EBADF) {
5360 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005361 if (newfd >= 0)
5362 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005363 errno = i;
5364 ash_msg_and_raise_error("%d: %m", fd);
5365 /* NOTREACHED */
5366 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005367 /* EBADF: it is not open - good, remember to close it */
5368 remember_to_close:
5369 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005370 } else { /* fd is open, save its copy */
5371 /* "exec fd>&-" should not close fds
5372 * which point to script file(s).
5373 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005374 if (is_hidden_fd(sv, fd))
5375 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005376 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005377 if (fd == 2)
5378 copied_fd2 = i;
5379 sv->two_fd[sv_pos].orig = fd;
5380 sv->two_fd[sv_pos].copy = i;
5381 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005382 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005383 if (newfd < 0) {
5384 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005385 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005386 /* Don't want to trigger debugging */
5387 if (fd != -1)
5388 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005389 } else {
5390 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005391 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005392 } else if (fd != newfd) { /* move newfd to fd */
5393 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005394#if ENABLE_ASH_BASH_COMPAT
5395 if (!(redir->nfile.type == NTO2 && fd == 2))
5396#endif
5397 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005398 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005399#if ENABLE_ASH_BASH_COMPAT
5400 if (redir->nfile.type == NTO2 && fd == 1) {
5401 /* We already redirected it to fd 1, now copy it to 2 */
5402 newfd = 1;
5403 fd = 2;
5404 goto redirect_more;
5405 }
5406#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005407 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005408
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005409 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005410 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5411 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005412}
5413
5414/*
5415 * Undo the effects of the last redirection.
5416 */
5417static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005418popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005419{
5420 struct redirtab *rp;
5421 int i;
5422
Ron Yorston95650a82015-10-30 19:07:37 +00005423 if (--g_nullredirs >= 0 || redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005424 return;
5425 INT_OFF;
5426 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005427 for (i = 0; i < rp->pair_count; i++) {
5428 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005429 int copy = rp->two_fd[i].copy;
5430 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005431 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005432 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005433 continue;
5434 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005435 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005436 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005437 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005438 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005439 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005440 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005441 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005442 }
5443 }
5444 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005445 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005446 free(rp);
5447 INT_ON;
5448}
5449
5450/*
5451 * Undo all redirections. Called on error or interrupt.
5452 */
5453
5454/*
5455 * Discard all saved file descriptors.
5456 */
5457static void
5458clearredir(int drop)
5459{
5460 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005461 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005462 if (!redirlist)
5463 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005464 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005465 }
5466}
5467
5468static int
5469redirectsafe(union node *redir, int flags)
5470{
5471 int err;
5472 volatile int saveint;
5473 struct jmploc *volatile savehandler = exception_handler;
5474 struct jmploc jmploc;
5475
5476 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005477 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5478 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005479 if (!err) {
5480 exception_handler = &jmploc;
5481 redirect(redir, flags);
5482 }
5483 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005484 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005485 longjmp(exception_handler->loc, 1);
5486 RESTORE_INT(saveint);
5487 return err;
5488}
5489
5490
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005491/* ============ Routines to expand arguments to commands
5492 *
5493 * We have to deal with backquotes, shell variables, and file metacharacters.
5494 */
5495
Mike Frysinger98c52642009-04-02 10:02:37 +00005496#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005497static arith_t
5498ash_arith(const char *s)
5499{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005500 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005501 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005502
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005503 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005504 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005505 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005506
5507 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005508 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005509 if (math_state.errmsg)
5510 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005511 INT_ON;
5512
5513 return result;
5514}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005515#endif
5516
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005517/*
5518 * expandarg flags
5519 */
5520#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5521#define EXP_TILDE 0x2 /* do normal tilde expansion */
5522#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5523#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5524#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005525#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005526#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5527#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005528#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005529/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005530 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005531 */
5532#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5533#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005534#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5535#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005536#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005537
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005538/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005539#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005540/* Do not skip NUL characters. */
5541#define QUOTES_KEEPNUL EXP_TILDE
5542
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005543/*
5544 * Structure specifying which parts of the string should be searched
5545 * for IFS characters.
5546 */
5547struct ifsregion {
5548 struct ifsregion *next; /* next region in list */
5549 int begoff; /* offset of start of region */
5550 int endoff; /* offset of end of region */
5551 int nulonly; /* search for nul bytes only */
5552};
5553
5554struct arglist {
5555 struct strlist *list;
5556 struct strlist **lastp;
5557};
5558
5559/* output of current string */
5560static char *expdest;
5561/* list of back quote expressions */
5562static struct nodelist *argbackq;
5563/* first struct in list of ifs regions */
5564static struct ifsregion ifsfirst;
5565/* last struct in list */
5566static struct ifsregion *ifslastp;
5567/* holds expanded arg list */
5568static struct arglist exparg;
5569
5570/*
5571 * Our own itoa().
5572 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005573#if !ENABLE_SH_MATH_SUPPORT
5574/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5575typedef long arith_t;
5576# define ARITH_FMT "%ld"
5577#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005578static int
5579cvtnum(arith_t num)
5580{
5581 int len;
5582
Denys Vlasenko9c541002015-10-07 15:44:36 +02005583 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5584 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005585 STADJUST(len, expdest);
5586 return len;
5587}
5588
5589static size_t
5590esclen(const char *start, const char *p)
5591{
5592 size_t esc = 0;
5593
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005594 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005595 esc++;
5596 }
5597 return esc;
5598}
5599
5600/*
5601 * Remove any CTLESC characters from a string.
5602 */
5603static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005604rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005605{
Ron Yorston417622c2015-05-18 09:59:14 +02005606 static const char qchars[] ALIGN1 = {
5607 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005608
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005609 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005610 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005611 unsigned protect_against_glob;
5612 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005613 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005614
Ron Yorston417622c2015-05-18 09:59:14 +02005615 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005616 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005617 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005618
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005619 q = p;
5620 r = str;
5621 if (flag & RMESCAPE_ALLOC) {
5622 size_t len = p - str;
5623 size_t fulllen = len + strlen(p) + 1;
5624
5625 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005626 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005627 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005628 /* p and str may be invalidated by makestrspace */
5629 str = (char *)stackblock() + strloc;
5630 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005631 } else if (flag & RMESCAPE_HEAP) {
5632 r = ckmalloc(fulllen);
5633 } else {
5634 r = stalloc(fulllen);
5635 }
5636 q = r;
5637 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005638 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005639 }
5640 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005641
Ron Yorston549deab2015-05-18 09:57:51 +02005642 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005643 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005644 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005645 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005646 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005647// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005648 inquotes = ~inquotes;
5649 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005650 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005651 continue;
5652 }
Ron Yorston549deab2015-05-18 09:57:51 +02005653 if ((unsigned char)*p == CTLESC) {
5654 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005655#if DEBUG
5656 if (*p == '\0')
5657 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5658#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005659 if (protect_against_glob) {
5660 *q++ = '\\';
5661 }
5662 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005663 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005664 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005665 goto copy;
5666 }
Ron Yorston417622c2015-05-18 09:59:14 +02005667#if ENABLE_ASH_BASH_COMPAT
5668 else if (*p == '/' && slash) {
5669 /* stop handling globbing and mark location of slash */
5670 globbing = slash = 0;
5671 *p = CTLESC;
5672 }
5673#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005674 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005675 copy:
5676 *q++ = *p++;
5677 }
5678 *q = '\0';
5679 if (flag & RMESCAPE_GROW) {
5680 expdest = r;
5681 STADJUST(q - r + 1, expdest);
5682 }
5683 return r;
5684}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005685#define pmatch(a, b) !fnmatch((a), (b), 0)
5686
5687/*
5688 * Prepare a pattern for a expmeta (internal glob(3)) call.
5689 *
5690 * Returns an stalloced string.
5691 */
5692static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005693preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005694{
Ron Yorston549deab2015-05-18 09:57:51 +02005695 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005696}
5697
5698/*
5699 * Put a string on the stack.
5700 */
5701static void
5702memtodest(const char *p, size_t len, int syntax, int quotes)
5703{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005704 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005705
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005706 if (!len)
5707 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005708
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005709 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5710
5711 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005712 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005713 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005714 int n = SIT(c, syntax);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005715 if ((quotes & QUOTES_ESC)
5716 && ((n == CCTL)
5717 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5718 && n == CBACK)
5719 )
5720 ) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005721 USTPUTC(CTLESC, q);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005722 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005723 } else if (!(quotes & QUOTES_KEEPNUL))
5724 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005725 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005726 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005727
5728 expdest = q;
5729}
5730
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005731static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005732strtodest(const char *p, int syntax, int quotes)
5733{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005734 size_t len = strlen(p);
5735 memtodest(p, len, syntax, quotes);
5736 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005737}
5738
5739/*
5740 * Record the fact that we have to scan this region of the
5741 * string for IFS characters.
5742 */
5743static void
5744recordregion(int start, int end, int nulonly)
5745{
5746 struct ifsregion *ifsp;
5747
5748 if (ifslastp == NULL) {
5749 ifsp = &ifsfirst;
5750 } else {
5751 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005752 ifsp = ckzalloc(sizeof(*ifsp));
5753 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005754 ifslastp->next = ifsp;
5755 INT_ON;
5756 }
5757 ifslastp = ifsp;
5758 ifslastp->begoff = start;
5759 ifslastp->endoff = end;
5760 ifslastp->nulonly = nulonly;
5761}
5762
5763static void
5764removerecordregions(int endoff)
5765{
5766 if (ifslastp == NULL)
5767 return;
5768
5769 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005770 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005771 struct ifsregion *ifsp;
5772 INT_OFF;
5773 ifsp = ifsfirst.next->next;
5774 free(ifsfirst.next);
5775 ifsfirst.next = ifsp;
5776 INT_ON;
5777 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005778 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005779 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005780 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005781 ifslastp = &ifsfirst;
5782 ifsfirst.endoff = endoff;
5783 }
5784 return;
5785 }
5786
5787 ifslastp = &ifsfirst;
5788 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005789 ifslastp = ifslastp->next;
5790 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005791 struct ifsregion *ifsp;
5792 INT_OFF;
5793 ifsp = ifslastp->next->next;
5794 free(ifslastp->next);
5795 ifslastp->next = ifsp;
5796 INT_ON;
5797 }
5798 if (ifslastp->endoff > endoff)
5799 ifslastp->endoff = endoff;
5800}
5801
5802static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005803exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005804{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005805 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005806 char *name;
5807 struct passwd *pw;
5808 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005809 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005810
5811 name = p + 1;
5812
5813 while ((c = *++p) != '\0') {
5814 switch (c) {
5815 case CTLESC:
5816 return startp;
5817 case CTLQUOTEMARK:
5818 return startp;
5819 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005820 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005821 goto done;
5822 break;
5823 case '/':
5824 case CTLENDVAR:
5825 goto done;
5826 }
5827 }
5828 done:
5829 *p = '\0';
5830 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005831 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005832 } else {
5833 pw = getpwnam(name);
5834 if (pw == NULL)
5835 goto lose;
5836 home = pw->pw_dir;
5837 }
5838 if (!home || !*home)
5839 goto lose;
5840 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005841 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005842 return p;
5843 lose:
5844 *p = c;
5845 return startp;
5846}
5847
5848/*
5849 * Execute a command inside back quotes. If it's a builtin command, we
5850 * want to save its output in a block obtained from malloc. Otherwise
5851 * we fork off a subprocess and get the output of the command via a pipe.
5852 * Should be called with interrupts off.
5853 */
5854struct backcmd { /* result of evalbackcmd */
5855 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005856 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005857 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005858 struct job *jp; /* job structure for command */
5859};
5860
5861/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005862static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005863#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02005864static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005865
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005866static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005867evalbackcmd(union node *n, struct backcmd *result)
5868{
5869 int saveherefd;
5870
5871 result->fd = -1;
5872 result->buf = NULL;
5873 result->nleft = 0;
5874 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005875 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005876 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005877
5878 saveherefd = herefd;
5879 herefd = -1;
5880
5881 {
5882 int pip[2];
5883 struct job *jp;
5884
5885 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005886 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005887 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005888 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5889 FORCE_INT_ON;
5890 close(pip[0]);
5891 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005892 /*close(1);*/
5893 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005894 close(pip[1]);
5895 }
5896 eflag = 0;
5897 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5898 /* NOTREACHED */
5899 }
5900 close(pip[1]);
5901 result->fd = pip[0];
5902 result->jp = jp;
5903 }
5904 herefd = saveherefd;
5905 out:
5906 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5907 result->fd, result->buf, result->nleft, result->jp));
5908}
5909
5910/*
5911 * Expand stuff in backwards quotes.
5912 */
5913static void
Ron Yorston549deab2015-05-18 09:57:51 +02005914expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005915{
5916 struct backcmd in;
5917 int i;
5918 char buf[128];
5919 char *p;
5920 char *dest;
5921 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02005922 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005923 struct stackmark smark;
5924
5925 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02005926 startloc = expdest - (char *)stackblock();
5927 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005928 evalbackcmd(cmd, &in);
5929 popstackmark(&smark);
5930
5931 p = in.buf;
5932 i = in.nleft;
5933 if (i == 0)
5934 goto read;
5935 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02005936 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005937 read:
5938 if (in.fd < 0)
5939 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01005940 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005941 TRACE(("expbackq: read returns %d\n", i));
5942 if (i <= 0)
5943 break;
5944 p = buf;
5945 }
5946
Denis Vlasenko60818682007-09-28 22:07:23 +00005947 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005948 if (in.fd >= 0) {
5949 close(in.fd);
5950 back_exitstatus = waitforjob(in.jp);
5951 }
5952 INT_ON;
5953
5954 /* Eat all trailing newlines */
5955 dest = expdest;
5956 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5957 STUNPUTC(dest);
5958 expdest = dest;
5959
Ron Yorston549deab2015-05-18 09:57:51 +02005960 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005961 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005962 TRACE(("evalbackq: size:%d:'%.*s'\n",
5963 (int)((dest - (char *)stackblock()) - startloc),
5964 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005965 stackblock() + startloc));
5966}
5967
Mike Frysinger98c52642009-04-02 10:02:37 +00005968#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005969/*
5970 * Expand arithmetic expression. Backup to start of expression,
5971 * evaluate, place result in (backed up) result, adjust string position.
5972 */
5973static void
Ron Yorston549deab2015-05-18 09:57:51 +02005974expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005975{
5976 char *p, *start;
5977 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005978 int len;
5979
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005980 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005981
5982 /*
5983 * This routine is slightly over-complicated for
5984 * efficiency. Next we scan backwards looking for the
5985 * start of arithmetic.
5986 */
5987 start = stackblock();
5988 p = expdest - 1;
5989 *p = '\0';
5990 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005991 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005992 int esc;
5993
Denys Vlasenkocd716832009-11-28 22:14:02 +01005994 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005995 p--;
5996#if DEBUG
5997 if (p < start) {
5998 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5999 }
6000#endif
6001 }
6002
6003 esc = esclen(start, p);
6004 if (!(esc % 2)) {
6005 break;
6006 }
6007
6008 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006009 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006010
6011 begoff = p - start;
6012
6013 removerecordregions(begoff);
6014
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006015 expdest = p;
6016
Ron Yorston549deab2015-05-18 09:57:51 +02006017 if (flag & QUOTES_ESC)
6018 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006019
Ron Yorston549deab2015-05-18 09:57:51 +02006020 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006021
Ron Yorston549deab2015-05-18 09:57:51 +02006022 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006023 recordregion(begoff, begoff + len, 0);
6024}
6025#endif
6026
6027/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006028static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006029
6030/*
6031 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6032 * characters to allow for further processing. Otherwise treat
6033 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006034 *
6035 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6036 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6037 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006038 */
6039static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006040argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006041{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006042 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006043 '=',
6044 ':',
6045 CTLQUOTEMARK,
6046 CTLENDVAR,
6047 CTLESC,
6048 CTLVAR,
6049 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006050#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006051 CTLENDARI,
6052#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006053 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006054 };
6055 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006056 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006057 int inquotes;
6058 size_t length;
6059 int startloc;
6060
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006061 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006062 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006063 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006064 reject++;
6065 }
6066 inquotes = 0;
6067 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006068 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069 char *q;
6070
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006071 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006072 tilde:
6073 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006074 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006075 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006076 }
6077 start:
6078 startloc = expdest - (char *)stackblock();
6079 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006080 unsigned char c;
6081
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006082 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006083 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006084 if (c) {
6085 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006086 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006087 ) {
6088 /* c == '=' || c == ':' || c == CTLENDARI */
6089 length++;
6090 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006091 }
6092 if (length > 0) {
6093 int newloc;
6094 expdest = stack_nputstr(p, length, expdest);
6095 newloc = expdest - (char *)stackblock();
6096 if (breakall && !inquotes && newloc > startloc) {
6097 recordregion(startloc, newloc, 0);
6098 }
6099 startloc = newloc;
6100 }
6101 p += length + 1;
6102 length = 0;
6103
6104 switch (c) {
6105 case '\0':
6106 goto breakloop;
6107 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006108 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006109 p--;
6110 continue;
6111 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006112 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006113 reject++;
6114 /* fall through */
6115 case ':':
6116 /*
6117 * sort of a hack - expand tildes in variable
6118 * assignments (after the first '=' and after ':'s).
6119 */
6120 if (*--p == '~') {
6121 goto tilde;
6122 }
6123 continue;
6124 }
6125
6126 switch (c) {
6127 case CTLENDVAR: /* ??? */
6128 goto breakloop;
6129 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006130 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006131 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006132 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6133 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006134 goto start;
6135 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006136 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006137 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006138 p--;
6139 length++;
6140 startloc++;
6141 }
6142 break;
6143 case CTLESC:
6144 startloc++;
6145 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006146
6147 /*
6148 * Quoted parameter expansion pattern: remove quote
6149 * unless inside inner quotes or we have a literal
6150 * backslash.
6151 */
6152 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6153 EXP_QPAT && *p != '\\')
6154 break;
6155
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006156 goto addquote;
6157 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006158 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006159 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006160 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006161 goto start;
6162 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006163 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006164 argbackq = argbackq->next;
6165 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006166#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006167 case CTLENDARI:
6168 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006169 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006170 goto start;
6171#endif
6172 }
6173 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006174 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006175}
6176
6177static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006178scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6179 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006180{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006181 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006182 char c;
6183
6184 loc = startp;
6185 loc2 = rmesc;
6186 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006187 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006188 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006189
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006190 c = *loc2;
6191 if (zero) {
6192 *loc2 = '\0';
6193 s = rmesc;
6194 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006195 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006196
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006197 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006198 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006199 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006200 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006201 loc++;
6202 loc++;
6203 loc2++;
6204 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006205 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006206}
6207
6208static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006209scanright(char *startp, char *rmesc, char *rmescend,
6210 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006211{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006212#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6213 int try2optimize = match_at_start;
6214#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006215 int esc = 0;
6216 char *loc;
6217 char *loc2;
6218
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006219 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6220 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6221 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6222 * Logic:
6223 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6224 * and on each iteration they go back two/one char until they reach the beginning.
6225 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6226 */
6227 /* TODO: document in what other circumstances we are called. */
6228
6229 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006230 int match;
6231 char c = *loc2;
6232 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006233 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006234 *loc2 = '\0';
6235 s = rmesc;
6236 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006237 match = pmatch(pattern, s);
6238 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006239 *loc2 = c;
6240 if (match)
6241 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006242#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6243 if (try2optimize) {
6244 /* Maybe we can optimize this:
6245 * if pattern ends with unescaped *, we can avoid checking
6246 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6247 * it wont match truncated "raw_value_of_" strings too.
6248 */
6249 unsigned plen = strlen(pattern);
6250 /* Does it end with "*"? */
6251 if (plen != 0 && pattern[--plen] == '*') {
6252 /* "xxxx*" is not escaped */
6253 /* "xxx\*" is escaped */
6254 /* "xx\\*" is not escaped */
6255 /* "x\\\*" is escaped */
6256 int slashes = 0;
6257 while (plen != 0 && pattern[--plen] == '\\')
6258 slashes++;
6259 if (!(slashes & 1))
6260 break; /* ends with unescaped "*" */
6261 }
6262 try2optimize = 0;
6263 }
6264#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265 loc--;
6266 if (quotes) {
6267 if (--esc < 0) {
6268 esc = esclen(startp, loc);
6269 }
6270 if (esc % 2) {
6271 esc--;
6272 loc--;
6273 }
6274 }
6275 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006276 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006277}
6278
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006279static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006280static void
6281varunset(const char *end, const char *var, const char *umsg, int varflags)
6282{
6283 const char *msg;
6284 const char *tail;
6285
6286 tail = nullstr;
6287 msg = "parameter not set";
6288 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006289 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006290 if (varflags & VSNUL)
6291 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006292 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006293 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006294 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006295 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006296 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006297}
6298
6299static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006300subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006301 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006302{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006303 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006304 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006305 char *startp;
6306 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006308 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006309 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006310 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006311 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006312 int amount, resetloc;
6313 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006314 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006315 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006316
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006317 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6318 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006319
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006320 herefd = -1;
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006321 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006322 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6323 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006324 STPUTC('\0', expdest);
6325 herefd = saveherefd;
6326 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006327 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006328
6329 switch (subtype) {
6330 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006331 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006332 amount = startp - expdest;
6333 STADJUST(amount, expdest);
6334 return startp;
6335
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006336 case VSQUESTION:
6337 varunset(p, varname, startp, varflags);
6338 /* NOTREACHED */
6339
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006340#if ENABLE_ASH_BASH_COMPAT
6341 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006342//TODO: support more general format ${v:EXPR:EXPR},
6343// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006344 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006345 /* Read POS in ${var:POS:LEN} */
6346 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006347 len = str - startp - 1;
6348
6349 /* *loc != '\0', guaranteed by parser */
6350 if (quotes) {
6351 char *ptr;
6352
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006353 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006354 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006355 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006356 len--;
6357 ptr++;
6358 }
6359 }
6360 }
6361 orig_len = len;
6362
6363 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006364 /* ${var::LEN} */
6365 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006366 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006367 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006368 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006369 while (*loc && *loc != ':') {
6370 /* TODO?
6371 * bash complains on: var=qwe; echo ${var:1a:123}
6372 if (!isdigit(*loc))
6373 ash_msg_and_raise_error(msg_illnum, str);
6374 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006375 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006376 }
6377 if (*loc++ == ':') {
6378 len = number(loc);
6379 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006380 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006381 if (pos < 0) {
6382 /* ${VAR:$((-n)):l} starts n chars from the end */
6383 pos = orig_len + pos;
6384 }
6385 if ((unsigned)pos >= orig_len) {
6386 /* apart from obvious ${VAR:999999:l},
6387 * covers ${VAR:$((-9999999)):l} - result is ""
6388 * (bash-compat)
6389 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006390 pos = 0;
6391 len = 0;
6392 }
6393 if (len > (orig_len - pos))
6394 len = orig_len - pos;
6395
6396 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006397 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006398 str++;
6399 }
6400 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006401 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006402 *loc++ = *str++;
6403 *loc++ = *str++;
6404 }
6405 *loc = '\0';
6406 amount = loc - expdest;
6407 STADJUST(amount, expdest);
6408 return loc;
6409#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006410 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006411
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006412 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006413
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006414 /* We'll comeback here if we grow the stack while handling
6415 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6416 * stack will need rebasing, and we'll need to remove our work
6417 * areas each time
6418 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006419 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006420
6421 amount = expdest - ((char *)stackblock() + resetloc);
6422 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006423 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006424
6425 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006426 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006427 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006428 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429 if (rmesc != startp) {
6430 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006431 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006432 }
6433 }
6434 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006435 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006436 /*
6437 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6438 * The result is a_\_z_c (not a\_\_z_c)!
6439 *
6440 * The search pattern and replace string treat backslashes differently!
6441 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6442 * and string. It's only used on the first call.
6443 */
6444 preglob(str, IF_ASH_BASH_COMPAT(
6445 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6446 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006447
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006448#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006449 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006450 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006451 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006452
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006453 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006454 repl = strchr(str, CTLESC);
6455 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006456 *repl++ = '\0';
6457 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006458 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006459 }
Ron Yorston417622c2015-05-18 09:59:14 +02006460 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006461
6462 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006463 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006464 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006465
6466 len = 0;
6467 idx = startp;
6468 end = str - 1;
6469 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006470 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006471 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006472 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006473 if (!loc) {
6474 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006475 char *restart_detect = stackblock();
6476 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006477 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006478 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006479 idx++;
6480 len++;
6481 STPUTC(*idx, expdest);
6482 }
6483 if (stackblock() != restart_detect)
6484 goto restart;
6485 idx++;
6486 len++;
6487 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006488 /* continue; - prone to quadratic behavior, smarter code: */
6489 if (idx >= end)
6490 break;
6491 if (str[0] == '*') {
6492 /* Pattern is "*foo". If "*foo" does not match "long_string",
6493 * it would never match "ong_string" etc, no point in trying.
6494 */
6495 goto skip_matching;
6496 }
6497 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006498 }
6499
6500 if (subtype == VSREPLACEALL) {
6501 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006502 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006503 idx++;
6504 idx++;
6505 rmesc++;
6506 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006507 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006508 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006509 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006510
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006511 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006512 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006513 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006514 if (quotes && *loc == '\\') {
6515 STPUTC(CTLESC, expdest);
6516 len++;
6517 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006518 STPUTC(*loc, expdest);
6519 if (stackblock() != restart_detect)
6520 goto restart;
6521 len++;
6522 }
6523
6524 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006525 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006526 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006527 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006528 STPUTC(*idx, expdest);
6529 if (stackblock() != restart_detect)
6530 goto restart;
6531 len++;
6532 idx++;
6533 }
6534 break;
6535 }
6536 }
6537
6538 /* We've put the replaced text into a buffer at workloc, now
6539 * move it to the right place and adjust the stack.
6540 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006541 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006542 startp = (char *)stackblock() + startloc;
6543 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006544 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006545 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006546 STADJUST(-amount, expdest);
6547 return startp;
6548 }
6549#endif /* ENABLE_ASH_BASH_COMPAT */
6550
6551 subtype -= VSTRIMRIGHT;
6552#if DEBUG
6553 if (subtype < 0 || subtype > 7)
6554 abort();
6555#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006556 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006557 zero = subtype >> 1;
6558 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6559 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6560
6561 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6562 if (loc) {
6563 if (zero) {
6564 memmove(startp, loc, str - loc);
6565 loc = startp + (str - loc) - 1;
6566 }
6567 *loc = '\0';
6568 amount = loc - expdest;
6569 STADJUST(amount, expdest);
6570 }
6571 return loc;
6572}
6573
6574/*
6575 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006576 * name parameter (examples):
6577 * ash -c 'echo $1' name:'1='
6578 * ash -c 'echo $qwe' name:'qwe='
6579 * ash -c 'echo $$' name:'$='
6580 * ash -c 'echo ${$}' name:'$='
6581 * ash -c 'echo ${$##q}' name:'$=q'
6582 * ash -c 'echo ${#$}' name:'$='
6583 * note: examples with bad shell syntax:
6584 * ash -c 'echo ${#$1}' name:'$=1'
6585 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006586 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006587static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006588varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006589{
Mike Frysinger98c52642009-04-02 10:02:37 +00006590 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006591 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006592 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006593 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006594 int sep;
Ron Yorston549deab2015-05-18 09:57:51 +02006595 int quoted = flags & EXP_QUOTED;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006596 int subtype = varflags & VSTYPE;
6597 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6598 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006599 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006600
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006601 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
6602
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006603 switch (*name) {
6604 case '$':
6605 num = rootpid;
6606 goto numvar;
6607 case '?':
6608 num = exitstatus;
6609 goto numvar;
6610 case '#':
6611 num = shellparam.nparam;
6612 goto numvar;
6613 case '!':
6614 num = backgndpid;
6615 if (num == 0)
6616 return -1;
6617 numvar:
6618 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006619 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006620 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006621 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622 for (i = NOPTS - 1; i >= 0; i--) {
6623 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006624 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006625 len++;
6626 }
6627 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006628 check_1char_name:
6629#if 0
6630 /* handles cases similar to ${#$1} */
6631 if (name[2] != '\0')
6632 raise_error_syntax("bad substitution");
6633#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006634 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006635 case '@': {
6636 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006637 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006638
6639 if (quoted && (flags & EXP_FULL)) {
6640 /* note: this is not meant as PEOF value */
6641 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006642 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006643 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006644 /* fall through */
6645 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006646 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006647 param:
6648 ap = shellparam.p;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006649 sepc = sep;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006650 if (!ap)
6651 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006652 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006653 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006654
6655 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006656 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006657 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006658 }
6659 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006660 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006661 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006662 case '0':
6663 case '1':
6664 case '2':
6665 case '3':
6666 case '4':
6667 case '5':
6668 case '6':
6669 case '7':
6670 case '8':
6671 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006672 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006673 if (num < 0 || num > shellparam.nparam)
6674 return -1;
6675 p = num ? shellparam.p[num - 1] : arg0;
6676 goto value;
6677 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006678 /* NB: name has form "VAR=..." */
6679
6680 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6681 * which should be considered before we check variables. */
6682 if (var_str_list) {
6683 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6684 p = NULL;
6685 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006686 char *str, *eq;
6687 str = var_str_list->text;
6688 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006689 if (!eq) /* stop at first non-assignment */
6690 break;
6691 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006692 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006693 && strncmp(str, name, name_len) == 0
6694 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006695 p = eq;
6696 /* goto value; - WRONG! */
6697 /* think "A=1 A=2 B=$A" */
6698 }
6699 var_str_list = var_str_list->next;
6700 } while (var_str_list);
6701 if (p)
6702 goto value;
6703 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006704 p = lookupvar(name);
6705 value:
6706 if (!p)
6707 return -1;
6708
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006709 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006710#if ENABLE_UNICODE_SUPPORT
6711 if (subtype == VSLENGTH && len > 0) {
6712 reinit_unicode_for_ash();
6713 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006714 STADJUST(-len, expdest);
6715 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006716 len = unicode_strlen(p);
6717 }
6718 }
6719#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006720 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006721 }
6722
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006723 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006724 STADJUST(-len, expdest);
6725 return len;
6726}
6727
6728/*
6729 * Expand a variable, and return a pointer to the next character in the
6730 * input string.
6731 */
6732static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006733evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006734{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006735 char varflags;
6736 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006737 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006738 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006739 char *var;
6740 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006741 int startloc;
6742 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006743
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006744 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006745 subtype = varflags & VSTYPE;
Ron Yorston549deab2015-05-18 09:57:51 +02006746 quoted = flags & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006747 var = p;
6748 easy = (!quoted || (*var == '@' && shellparam.nparam));
6749 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006750 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006751
6752 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006753 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006754 if (varflags & VSNUL)
6755 varlen--;
6756
6757 if (subtype == VSPLUS) {
6758 varlen = -1 - varlen;
6759 goto vsplus;
6760 }
6761
6762 if (subtype == VSMINUS) {
6763 vsplus:
6764 if (varlen < 0) {
6765 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006766 p,
Ron Yorston549deab2015-05-18 09:57:51 +02006767 flags | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006768 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006769 );
6770 goto end;
6771 }
6772 if (easy)
6773 goto record;
6774 goto end;
6775 }
6776
6777 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6778 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006779 if (subevalvar(p, var, /* strloc: */ 0,
6780 subtype, startloc, varflags,
Ron Yorston549deab2015-05-18 09:57:51 +02006781 /* quotes: */ flags & ~QUOTES_ESC,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006782 var_str_list)
6783 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006784 varflags &= ~VSNUL;
6785 /*
6786 * Remove any recorded regions beyond
6787 * start of variable
6788 */
6789 removerecordregions(startloc);
6790 goto again;
6791 }
6792 goto end;
6793 }
6794 if (easy)
6795 goto record;
6796 goto end;
6797 }
6798
6799 if (varlen < 0 && uflag)
6800 varunset(p, var, 0, 0);
6801
6802 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006803 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006804 goto record;
6805 }
6806
6807 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006808 if (easy)
6809 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006810 goto end;
6811 }
6812
6813#if DEBUG
6814 switch (subtype) {
6815 case VSTRIMLEFT:
6816 case VSTRIMLEFTMAX:
6817 case VSTRIMRIGHT:
6818 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006819#if ENABLE_ASH_BASH_COMPAT
6820 case VSSUBSTR:
6821 case VSREPLACE:
6822 case VSREPLACEALL:
6823#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006824 break;
6825 default:
6826 abort();
6827 }
6828#endif
6829
6830 if (varlen >= 0) {
6831 /*
6832 * Terminate the string and start recording the pattern
6833 * right after it
6834 */
6835 STPUTC('\0', expdest);
6836 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006837 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006838 startloc, varflags, flags, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006839 int amount = expdest - (
6840 (char *)stackblock() + patloc - 1
6841 );
6842 STADJUST(-amount, expdest);
6843 }
6844 /* Remove any recorded regions beyond start of variable */
6845 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006846 record:
6847 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006848 }
6849
6850 end:
6851 if (subtype != VSNORMAL) { /* skip to end of alternative */
6852 int nesting = 1;
6853 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006854 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006855 if (c == CTLESC)
6856 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006857 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006858 if (varlen >= 0)
6859 argbackq = argbackq->next;
6860 } else if (c == CTLVAR) {
6861 if ((*p++ & VSTYPE) != VSNORMAL)
6862 nesting++;
6863 } else if (c == CTLENDVAR) {
6864 if (--nesting == 0)
6865 break;
6866 }
6867 }
6868 }
6869 return p;
6870}
6871
6872/*
6873 * Break the argument string into pieces based upon IFS and add the
6874 * strings to the argument list. The regions of the string to be
6875 * searched for IFS characters have been stored by recordregion.
6876 */
6877static void
6878ifsbreakup(char *string, struct arglist *arglist)
6879{
6880 struct ifsregion *ifsp;
6881 struct strlist *sp;
6882 char *start;
6883 char *p;
6884 char *q;
6885 const char *ifs, *realifs;
6886 int ifsspc;
6887 int nulonly;
6888
6889 start = string;
6890 if (ifslastp != NULL) {
6891 ifsspc = 0;
6892 nulonly = 0;
6893 realifs = ifsset() ? ifsval() : defifs;
6894 ifsp = &ifsfirst;
6895 do {
6896 p = string + ifsp->begoff;
6897 nulonly = ifsp->nulonly;
6898 ifs = nulonly ? nullstr : realifs;
6899 ifsspc = 0;
6900 while (p < string + ifsp->endoff) {
6901 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006902 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006903 p++;
6904 if (!strchr(ifs, *p)) {
6905 p++;
6906 continue;
6907 }
6908 if (!nulonly)
6909 ifsspc = (strchr(defifs, *p) != NULL);
6910 /* Ignore IFS whitespace at start */
6911 if (q == start && ifsspc) {
6912 p++;
6913 start = p;
6914 continue;
6915 }
6916 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006917 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006918 sp->text = start;
6919 *arglist->lastp = sp;
6920 arglist->lastp = &sp->next;
6921 p++;
6922 if (!nulonly) {
6923 for (;;) {
6924 if (p >= string + ifsp->endoff) {
6925 break;
6926 }
6927 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006928 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006929 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006930 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006931 p = q;
6932 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006933 }
6934 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006935 if (ifsspc) {
6936 p++;
6937 ifsspc = 0;
6938 } else {
6939 p = q;
6940 break;
6941 }
6942 } else
6943 p++;
6944 }
6945 }
6946 start = p;
6947 } /* while */
6948 ifsp = ifsp->next;
6949 } while (ifsp != NULL);
6950 if (nulonly)
6951 goto add;
6952 }
6953
6954 if (!*start)
6955 return;
6956
6957 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006958 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006959 sp->text = start;
6960 *arglist->lastp = sp;
6961 arglist->lastp = &sp->next;
6962}
6963
6964static void
6965ifsfree(void)
6966{
6967 struct ifsregion *p;
6968
6969 INT_OFF;
6970 p = ifsfirst.next;
6971 do {
6972 struct ifsregion *ifsp;
6973 ifsp = p->next;
6974 free(p);
6975 p = ifsp;
6976 } while (p);
6977 ifslastp = NULL;
6978 ifsfirst.next = NULL;
6979 INT_ON;
6980}
6981
6982/*
6983 * Add a file name to the list.
6984 */
6985static void
6986addfname(const char *name)
6987{
6988 struct strlist *sp;
6989
Denis Vlasenko597906c2008-02-20 16:38:54 +00006990 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02006991 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006992 *exparg.lastp = sp;
6993 exparg.lastp = &sp->next;
6994}
6995
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006996/* If we want to use glob() from libc... */
6997#if 1
6998
6999/* Add the result of glob() to the list */
7000static void
7001addglob(const glob_t *pglob)
7002{
7003 char **p = pglob->gl_pathv;
7004
7005 do {
7006 addfname(*p);
7007 } while (*++p);
7008}
7009static void
7010expandmeta(struct strlist *str /*, int flag*/)
7011{
7012 /* TODO - EXP_REDIR */
7013
7014 while (str) {
7015 char *p;
7016 glob_t pglob;
7017 int i;
7018
7019 if (fflag)
7020 goto nometa;
7021 INT_OFF;
7022 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7023 /*
7024 * GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7025 * TODO?: GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7026 */
7027 i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7028 if (p != str->text)
7029 free(p);
7030 switch (i) {
7031 case 0:
7032 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7033 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7034 goto nometa2;
7035 addglob(&pglob);
7036 globfree(&pglob);
7037 INT_ON;
7038 break;
7039 case GLOB_NOMATCH:
7040nometa2:
7041 globfree(&pglob);
7042 INT_ON;
7043nometa:
7044 *exparg.lastp = str;
7045 rmescapes(str->text, 0);
7046 exparg.lastp = &str->next;
7047 break;
7048 default: /* GLOB_NOSPACE */
7049 globfree(&pglob);
7050 INT_ON;
7051 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7052 }
7053 str = str->next;
7054 }
7055}
7056
7057#else
7058/* Homegrown globbing code. (dash also has both, uses homegrown one.) */
7059
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007060/*
7061 * Do metacharacter (i.e. *, ?, [...]) expansion.
7062 */
7063static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007064expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007065{
7066 char *p;
7067 const char *cp;
7068 char *start;
7069 char *endname;
7070 int metaflag;
7071 struct stat statb;
7072 DIR *dirp;
7073 struct dirent *dp;
7074 int atend;
7075 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007076 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007077
7078 metaflag = 0;
7079 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007080 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007081 if (*p == '*' || *p == '?')
7082 metaflag = 1;
7083 else if (*p == '[') {
7084 char *q = p + 1;
7085 if (*q == '!')
7086 q++;
7087 for (;;) {
7088 if (*q == '\\')
7089 q++;
7090 if (*q == '/' || *q == '\0')
7091 break;
7092 if (*++q == ']') {
7093 metaflag = 1;
7094 break;
7095 }
7096 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007097 } else {
7098 if (*p == '\\')
7099 esc++;
7100 if (p[esc] == '/') {
7101 if (metaflag)
7102 break;
7103 start = p + esc + 1;
7104 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007105 }
7106 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007107 if (metaflag == 0) { /* we've reached the end of the file name */
7108 if (enddir != expdir)
7109 metaflag++;
7110 p = name;
7111 do {
7112 if (*p == '\\')
7113 p++;
7114 *enddir++ = *p;
7115 } while (*p++);
7116 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7117 addfname(expdir);
7118 return;
7119 }
7120 endname = p;
7121 if (name < start) {
7122 p = name;
7123 do {
7124 if (*p == '\\')
7125 p++;
7126 *enddir++ = *p++;
7127 } while (p < start);
7128 }
7129 if (enddir == expdir) {
7130 cp = ".";
7131 } else if (enddir == expdir + 1 && *expdir == '/') {
7132 cp = "/";
7133 } else {
7134 cp = expdir;
7135 enddir[-1] = '\0';
7136 }
7137 dirp = opendir(cp);
7138 if (dirp == NULL)
7139 return;
7140 if (enddir != expdir)
7141 enddir[-1] = '/';
7142 if (*endname == 0) {
7143 atend = 1;
7144 } else {
7145 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007146 *endname = '\0';
7147 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007148 }
7149 matchdot = 0;
7150 p = start;
7151 if (*p == '\\')
7152 p++;
7153 if (*p == '.')
7154 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007155 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007156 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157 continue;
7158 if (pmatch(start, dp->d_name)) {
7159 if (atend) {
7160 strcpy(enddir, dp->d_name);
7161 addfname(expdir);
7162 } else {
7163 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7164 continue;
7165 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007166 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007167 }
7168 }
7169 }
7170 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007171 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007172 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007173}
7174
7175static struct strlist *
7176msort(struct strlist *list, int len)
7177{
7178 struct strlist *p, *q = NULL;
7179 struct strlist **lpp;
7180 int half;
7181 int n;
7182
7183 if (len <= 1)
7184 return list;
7185 half = len >> 1;
7186 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007187 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007188 q = p;
7189 p = p->next;
7190 }
7191 q->next = NULL; /* terminate first half of list */
7192 q = msort(list, half); /* sort first half of list */
7193 p = msort(p, len - half); /* sort second half */
7194 lpp = &list;
7195 for (;;) {
7196#if ENABLE_LOCALE_SUPPORT
7197 if (strcoll(p->text, q->text) < 0)
7198#else
7199 if (strcmp(p->text, q->text) < 0)
7200#endif
7201 {
7202 *lpp = p;
7203 lpp = &p->next;
7204 p = *lpp;
7205 if (p == NULL) {
7206 *lpp = q;
7207 break;
7208 }
7209 } else {
7210 *lpp = q;
7211 lpp = &q->next;
7212 q = *lpp;
7213 if (q == NULL) {
7214 *lpp = p;
7215 break;
7216 }
7217 }
7218 }
7219 return list;
7220}
7221
7222/*
7223 * Sort the results of file name expansion. It calculates the number of
7224 * strings to sort and then calls msort (short for merge sort) to do the
7225 * work.
7226 */
7227static struct strlist *
7228expsort(struct strlist *str)
7229{
7230 int len;
7231 struct strlist *sp;
7232
7233 len = 0;
7234 for (sp = str; sp; sp = sp->next)
7235 len++;
7236 return msort(str, len);
7237}
7238
7239static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007240expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007241{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007242 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007243 '*', '?', '[', 0
7244 };
7245 /* TODO - EXP_REDIR */
7246
7247 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007248 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007249 struct strlist **savelastp;
7250 struct strlist *sp;
7251 char *p;
7252
7253 if (fflag)
7254 goto nometa;
7255 if (!strpbrk(str->text, metachars))
7256 goto nometa;
7257 savelastp = exparg.lastp;
7258
7259 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007260 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007261 {
7262 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007263//BUGGY estimation of how long expanded name can be
7264 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007265 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007266 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007267 free(expdir);
7268 if (p != str->text)
7269 free(p);
7270 INT_ON;
7271 if (exparg.lastp == savelastp) {
7272 /*
7273 * no matches
7274 */
7275 nometa:
7276 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007277 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007278 exparg.lastp = &str->next;
7279 } else {
7280 *exparg.lastp = NULL;
7281 *savelastp = sp = expsort(*savelastp);
7282 while (sp->next != NULL)
7283 sp = sp->next;
7284 exparg.lastp = &sp->next;
7285 }
7286 str = str->next;
7287 }
7288}
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007289#endif /* our globbing code */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007290
7291/*
7292 * Perform variable substitution and command substitution on an argument,
7293 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7294 * perform splitting and file name expansion. When arglist is NULL, perform
7295 * here document expansion.
7296 */
7297static void
7298expandarg(union node *arg, struct arglist *arglist, int flag)
7299{
7300 struct strlist *sp;
7301 char *p;
7302
7303 argbackq = arg->narg.backquote;
7304 STARTSTACKSTR(expdest);
7305 ifsfirst.next = NULL;
7306 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007307 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007308 argstr(arg->narg.text, flag,
7309 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007310 p = _STPUTC('\0', expdest);
7311 expdest = p - 1;
7312 if (arglist == NULL) {
7313 return; /* here document expanded */
7314 }
7315 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007316 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007317 exparg.lastp = &exparg.list;
7318 /*
7319 * TODO - EXP_REDIR
7320 */
7321 if (flag & EXP_FULL) {
7322 ifsbreakup(p, &exparg);
7323 *exparg.lastp = NULL;
7324 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007325 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007326 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007327 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007328 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007329 TRACE(("expandarg: rmescapes:'%s'\n", p));
7330 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007331 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007332 sp->text = p;
7333 *exparg.lastp = sp;
7334 exparg.lastp = &sp->next;
7335 }
7336 if (ifsfirst.next)
7337 ifsfree();
7338 *exparg.lastp = NULL;
7339 if (exparg.list) {
7340 *arglist->lastp = exparg.list;
7341 arglist->lastp = exparg.lastp;
7342 }
7343}
7344
7345/*
7346 * Expand shell variables and backquotes inside a here document.
7347 */
7348static void
7349expandhere(union node *arg, int fd)
7350{
7351 herefd = fd;
Ron Yorston549deab2015-05-18 09:57:51 +02007352 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007353 full_write(fd, stackblock(), expdest - (char *)stackblock());
7354}
7355
7356/*
7357 * Returns true if the pattern matches the string.
7358 */
7359static int
7360patmatch(char *pattern, const char *string)
7361{
Ron Yorston549deab2015-05-18 09:57:51 +02007362 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007363}
7364
7365/*
7366 * See if a pattern matches in a case statement.
7367 */
7368static int
7369casematch(union node *pattern, char *val)
7370{
7371 struct stackmark smark;
7372 int result;
7373
7374 setstackmark(&smark);
7375 argbackq = pattern->narg.backquote;
7376 STARTSTACKSTR(expdest);
7377 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007378 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7379 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007380 STACKSTRNUL(expdest);
7381 result = patmatch(stackblock(), val);
7382 popstackmark(&smark);
7383 return result;
7384}
7385
7386
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007387/* ============ find_command */
7388
7389struct builtincmd {
7390 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007391 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007392 /* unsigned flags; */
7393};
7394#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007395/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007396 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007397#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007398#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007399
7400struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007401 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007402 union param {
7403 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007404 /* index >= 0 for commands without path (slashes) */
7405 /* (TODO: what exactly does the value mean? PATH position?) */
7406 /* index == -1 for commands with slashes */
7407 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007408 const struct builtincmd *cmd;
7409 struct funcnode *func;
7410 } u;
7411};
7412/* values of cmdtype */
7413#define CMDUNKNOWN -1 /* no entry in table for command */
7414#define CMDNORMAL 0 /* command is an executable program */
7415#define CMDFUNCTION 1 /* command is a shell function */
7416#define CMDBUILTIN 2 /* command is a shell builtin */
7417
7418/* action to find_command() */
7419#define DO_ERR 0x01 /* prints errors */
7420#define DO_ABS 0x02 /* checks absolute paths */
7421#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7422#define DO_ALTPATH 0x08 /* using alternate path */
7423#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7424
7425static void find_command(char *, struct cmdentry *, int, const char *);
7426
7427
7428/* ============ Hashing commands */
7429
7430/*
7431 * When commands are first encountered, they are entered in a hash table.
7432 * This ensures that a full path search will not have to be done for them
7433 * on each invocation.
7434 *
7435 * We should investigate converting to a linear search, even though that
7436 * would make the command name "hash" a misnomer.
7437 */
7438
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007439struct tblentry {
7440 struct tblentry *next; /* next entry in hash chain */
7441 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007442 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007443 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007444 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007445};
7446
Denis Vlasenko01631112007-12-16 17:20:38 +00007447static struct tblentry **cmdtable;
7448#define INIT_G_cmdtable() do { \
7449 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7450} while (0)
7451
7452static int builtinloc = -1; /* index in path of %builtin, or -1 */
7453
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007454
7455static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007456tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007457{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007458#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007459 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007460 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007461 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007462 while (*envp)
7463 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007464 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007465 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007466 /* re-exec ourselves with the new arguments */
7467 execve(bb_busybox_exec_path, argv, envp);
7468 /* If they called chroot or otherwise made the binary no longer
7469 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007470 }
7471#endif
7472
7473 repeat:
7474#ifdef SYSV
7475 do {
7476 execve(cmd, argv, envp);
7477 } while (errno == EINTR);
7478#else
7479 execve(cmd, argv, envp);
7480#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007481 if (cmd == (char*) bb_busybox_exec_path) {
7482 /* We already visited ENOEXEC branch below, don't do it again */
7483//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007484 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007485 return;
7486 }
7487 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007488 /* Run "cmd" as a shell script:
7489 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7490 * "If the execve() function fails with ENOEXEC, the shell
7491 * shall execute a command equivalent to having a shell invoked
7492 * with the command name as its first operand,
7493 * with any remaining arguments passed to the new shell"
7494 *
7495 * That is, do not use $SHELL, user's shell, or /bin/sh;
7496 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007497 *
7498 * Note that bash reads ~80 chars of the file, and if it sees
7499 * a zero byte before it sees newline, it doesn't try to
7500 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007501 * message and exit code 126. For one, this prevents attempts
7502 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007503 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007504 char **ap;
7505 char **new;
7506
7507 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007508 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007509 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7510 new[0] = (char*) "ash";
7511 new[1] = cmd;
7512 ap = new + 2;
7513 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007514 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007515 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007516 argv = new;
7517 goto repeat;
7518 }
7519}
7520
7521/*
7522 * Exec a program. Never returns. If you change this routine, you may
7523 * have to change the find_command routine as well.
7524 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007525static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007526static void
7527shellexec(char **argv, const char *path, int idx)
7528{
7529 char *cmdname;
7530 int e;
7531 char **envp;
7532 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007533 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007534
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007535 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007536 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007537 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007538#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007539 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007540#endif
7541 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007542 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007543 if (applet_no >= 0) {
7544 /* We tried execing ourself, but it didn't work.
7545 * Maybe /proc/self/exe doesn't exist?
7546 * Try $PATH search.
7547 */
7548 goto try_PATH;
7549 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007550 e = errno;
7551 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007552 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007553 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007554 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007555 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007556 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007557 if (errno != ENOENT && errno != ENOTDIR)
7558 e = errno;
7559 }
7560 stunalloc(cmdname);
7561 }
7562 }
7563
7564 /* Map to POSIX errors */
7565 switch (e) {
7566 case EACCES:
7567 exerrno = 126;
7568 break;
7569 case ENOENT:
7570 exerrno = 127;
7571 break;
7572 default:
7573 exerrno = 2;
7574 break;
7575 }
7576 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007577 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7578 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007579 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7580 /* NOTREACHED */
7581}
7582
7583static void
7584printentry(struct tblentry *cmdp)
7585{
7586 int idx;
7587 const char *path;
7588 char *name;
7589
7590 idx = cmdp->param.index;
7591 path = pathval();
7592 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007593 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007594 stunalloc(name);
7595 } while (--idx >= 0);
7596 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7597}
7598
7599/*
7600 * Clear out command entries. The argument specifies the first entry in
7601 * PATH which has changed.
7602 */
7603static void
7604clearcmdentry(int firstchange)
7605{
7606 struct tblentry **tblp;
7607 struct tblentry **pp;
7608 struct tblentry *cmdp;
7609
7610 INT_OFF;
7611 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7612 pp = tblp;
7613 while ((cmdp = *pp) != NULL) {
7614 if ((cmdp->cmdtype == CMDNORMAL &&
7615 cmdp->param.index >= firstchange)
7616 || (cmdp->cmdtype == CMDBUILTIN &&
7617 builtinloc >= firstchange)
7618 ) {
7619 *pp = cmdp->next;
7620 free(cmdp);
7621 } else {
7622 pp = &cmdp->next;
7623 }
7624 }
7625 }
7626 INT_ON;
7627}
7628
7629/*
7630 * Locate a command in the command hash table. If "add" is nonzero,
7631 * add the command to the table if it is not already present. The
7632 * variable "lastcmdentry" is set to point to the address of the link
7633 * pointing to the entry, so that delete_cmd_entry can delete the
7634 * entry.
7635 *
7636 * Interrupts must be off if called with add != 0.
7637 */
7638static struct tblentry **lastcmdentry;
7639
7640static struct tblentry *
7641cmdlookup(const char *name, int add)
7642{
7643 unsigned int hashval;
7644 const char *p;
7645 struct tblentry *cmdp;
7646 struct tblentry **pp;
7647
7648 p = name;
7649 hashval = (unsigned char)*p << 4;
7650 while (*p)
7651 hashval += (unsigned char)*p++;
7652 hashval &= 0x7FFF;
7653 pp = &cmdtable[hashval % CMDTABLESIZE];
7654 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7655 if (strcmp(cmdp->cmdname, name) == 0)
7656 break;
7657 pp = &cmdp->next;
7658 }
7659 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007660 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7661 + strlen(name)
7662 /* + 1 - already done because
7663 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007664 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007665 cmdp->cmdtype = CMDUNKNOWN;
7666 strcpy(cmdp->cmdname, name);
7667 }
7668 lastcmdentry = pp;
7669 return cmdp;
7670}
7671
7672/*
7673 * Delete the command entry returned on the last lookup.
7674 */
7675static void
7676delete_cmd_entry(void)
7677{
7678 struct tblentry *cmdp;
7679
7680 INT_OFF;
7681 cmdp = *lastcmdentry;
7682 *lastcmdentry = cmdp->next;
7683 if (cmdp->cmdtype == CMDFUNCTION)
7684 freefunc(cmdp->param.func);
7685 free(cmdp);
7686 INT_ON;
7687}
7688
7689/*
7690 * Add a new command entry, replacing any existing command entry for
7691 * the same name - except special builtins.
7692 */
7693static void
7694addcmdentry(char *name, struct cmdentry *entry)
7695{
7696 struct tblentry *cmdp;
7697
7698 cmdp = cmdlookup(name, 1);
7699 if (cmdp->cmdtype == CMDFUNCTION) {
7700 freefunc(cmdp->param.func);
7701 }
7702 cmdp->cmdtype = entry->cmdtype;
7703 cmdp->param = entry->u;
7704 cmdp->rehash = 0;
7705}
7706
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007707static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007708hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007709{
7710 struct tblentry **pp;
7711 struct tblentry *cmdp;
7712 int c;
7713 struct cmdentry entry;
7714 char *name;
7715
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007716 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007717 clearcmdentry(0);
7718 return 0;
7719 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007720
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007721 if (*argptr == NULL) {
7722 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7723 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7724 if (cmdp->cmdtype == CMDNORMAL)
7725 printentry(cmdp);
7726 }
7727 }
7728 return 0;
7729 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007730
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007731 c = 0;
7732 while ((name = *argptr) != NULL) {
7733 cmdp = cmdlookup(name, 0);
7734 if (cmdp != NULL
7735 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007736 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7737 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007738 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007739 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007740 find_command(name, &entry, DO_ERR, pathval());
7741 if (entry.cmdtype == CMDUNKNOWN)
7742 c = 1;
7743 argptr++;
7744 }
7745 return c;
7746}
7747
7748/*
7749 * Called when a cd is done. Marks all commands so the next time they
7750 * are executed they will be rehashed.
7751 */
7752static void
7753hashcd(void)
7754{
7755 struct tblentry **pp;
7756 struct tblentry *cmdp;
7757
7758 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7759 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007760 if (cmdp->cmdtype == CMDNORMAL
7761 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007762 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007763 && builtinloc > 0)
7764 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007765 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007766 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007767 }
7768 }
7769}
7770
7771/*
7772 * Fix command hash table when PATH changed.
7773 * Called before PATH is changed. The argument is the new value of PATH;
7774 * pathval() still returns the old value at this point.
7775 * Called with interrupts off.
7776 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007777static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007778changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007779{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007780 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007781 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007782 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007783 int idx_bltin;
7784
7785 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007786 firstchange = 9999; /* assume no change */
7787 idx = 0;
7788 idx_bltin = -1;
7789 for (;;) {
7790 if (*old != *new) {
7791 firstchange = idx;
7792 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007793 || (*old == ':' && *new == '\0')
7794 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007795 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007796 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007797 old = new; /* ignore subsequent differences */
7798 }
7799 if (*new == '\0')
7800 break;
7801 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7802 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007803 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007804 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007805 new++;
7806 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007807 }
7808 if (builtinloc < 0 && idx_bltin >= 0)
7809 builtinloc = idx_bltin; /* zap builtins */
7810 if (builtinloc >= 0 && idx_bltin < 0)
7811 firstchange = 0;
7812 clearcmdentry(firstchange);
7813 builtinloc = idx_bltin;
7814}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007815enum {
7816 TEOF,
7817 TNL,
7818 TREDIR,
7819 TWORD,
7820 TSEMI,
7821 TBACKGND,
7822 TAND,
7823 TOR,
7824 TPIPE,
7825 TLP,
7826 TRP,
7827 TENDCASE,
7828 TENDBQUOTE,
7829 TNOT,
7830 TCASE,
7831 TDO,
7832 TDONE,
7833 TELIF,
7834 TELSE,
7835 TESAC,
7836 TFI,
7837 TFOR,
7838#if ENABLE_ASH_BASH_COMPAT
7839 TFUNCTION,
7840#endif
7841 TIF,
7842 TIN,
7843 TTHEN,
7844 TUNTIL,
7845 TWHILE,
7846 TBEGIN,
7847 TEND
7848};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007849typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007850
7851/* first char is indicating which tokens mark the end of a list */
7852static const char *const tokname_array[] = {
7853 "\1end of file",
7854 "\0newline",
7855 "\0redirection",
7856 "\0word",
7857 "\0;",
7858 "\0&",
7859 "\0&&",
7860 "\0||",
7861 "\0|",
7862 "\0(",
7863 "\1)",
7864 "\1;;",
7865 "\1`",
7866#define KWDOFFSET 13
7867 /* the following are keywords */
7868 "\0!",
7869 "\0case",
7870 "\1do",
7871 "\1done",
7872 "\1elif",
7873 "\1else",
7874 "\1esac",
7875 "\1fi",
7876 "\0for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007877#if ENABLE_ASH_BASH_COMPAT
7878 "\0function",
7879#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007880 "\0if",
7881 "\0in",
7882 "\1then",
7883 "\0until",
7884 "\0while",
7885 "\0{",
7886 "\1}",
7887};
7888
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007889/* Wrapper around strcmp for qsort/bsearch/... */
7890static int
7891pstrcmp(const void *a, const void *b)
7892{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007893 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007894}
7895
7896static const char *const *
7897findkwd(const char *s)
7898{
7899 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007900 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7901 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007902}
7903
7904/*
7905 * Locate and print what a word is...
7906 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007907static int
Ron Yorston3f221112015-08-03 13:47:33 +01007908describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007909{
7910 struct cmdentry entry;
7911 struct tblentry *cmdp;
7912#if ENABLE_ASH_ALIAS
7913 const struct alias *ap;
7914#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007915
7916 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007917
7918 if (describe_command_verbose) {
7919 out1str(command);
7920 }
7921
7922 /* First look at the keywords */
7923 if (findkwd(command)) {
7924 out1str(describe_command_verbose ? " is a shell keyword" : command);
7925 goto out;
7926 }
7927
7928#if ENABLE_ASH_ALIAS
7929 /* Then look at the aliases */
7930 ap = lookupalias(command, 0);
7931 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007932 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007933 out1str("alias ");
7934 printalias(ap);
7935 return 0;
7936 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007937 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007938 goto out;
7939 }
7940#endif
7941 /* Then check if it is a tracked alias */
7942 cmdp = cmdlookup(command, 0);
7943 if (cmdp != NULL) {
7944 entry.cmdtype = cmdp->cmdtype;
7945 entry.u = cmdp->param;
7946 } else {
7947 /* Finally use brute force */
7948 find_command(command, &entry, DO_ABS, path);
7949 }
7950
7951 switch (entry.cmdtype) {
7952 case CMDNORMAL: {
7953 int j = entry.u.index;
7954 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007955 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007956 p = command;
7957 } else {
7958 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007959 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007960 stunalloc(p);
7961 } while (--j >= 0);
7962 }
7963 if (describe_command_verbose) {
7964 out1fmt(" is%s %s",
7965 (cmdp ? " a tracked alias for" : nullstr), p
7966 );
7967 } else {
7968 out1str(p);
7969 }
7970 break;
7971 }
7972
7973 case CMDFUNCTION:
7974 if (describe_command_verbose) {
7975 out1str(" is a shell function");
7976 } else {
7977 out1str(command);
7978 }
7979 break;
7980
7981 case CMDBUILTIN:
7982 if (describe_command_verbose) {
7983 out1fmt(" is a %sshell builtin",
7984 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7985 "special " : nullstr
7986 );
7987 } else {
7988 out1str(command);
7989 }
7990 break;
7991
7992 default:
7993 if (describe_command_verbose) {
7994 out1str(": not found\n");
7995 }
7996 return 127;
7997 }
7998 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01007999 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008000 return 0;
8001}
8002
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008003static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008004typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008005{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008006 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008007 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008008 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008009
Denis Vlasenko46846e22007-05-20 13:08:31 +00008010 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008011 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008012 i++;
8013 verbose = 0;
8014 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008015 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008016 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008017 }
8018 return err;
8019}
8020
8021#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008022static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008023commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008024{
8025 int c;
8026 enum {
8027 VERIFY_BRIEF = 1,
8028 VERIFY_VERBOSE = 2,
8029 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008030 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008031
8032 while ((c = nextopt("pvV")) != '\0')
8033 if (c == 'V')
8034 verify |= VERIFY_VERBOSE;
8035 else if (c == 'v')
8036 verify |= VERIFY_BRIEF;
8037#if DEBUG
8038 else if (c != 'p')
8039 abort();
8040#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008041 else
8042 path = bb_default_path;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008043 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8044 if (verify && (*argptr != NULL)) {
Ron Yorston3f221112015-08-03 13:47:33 +01008045 return describe_command(*argptr, path, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008046 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008047
8048 return 0;
8049}
8050#endif
8051
8052
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008053/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00008054
Denis Vlasenko340299a2008-11-21 10:36:36 +00008055static int funcblocksize; /* size of structures in function */
8056static int funcstringsize; /* size of strings in node */
8057static void *funcblock; /* block to allocate function from */
8058static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008059
Eric Andersencb57d552001-06-28 07:25:16 +00008060/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008061#define EV_EXIT 01 /* exit after evaluating tree */
8062#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008063
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008064static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008065 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8066 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8067 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8068 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8069 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8070 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8071 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8072 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8073 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8074 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8075 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8076 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8077 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8078 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8079 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8080 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8081 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008082#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008083 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008084#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008085 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8086 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8087 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8088 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8089 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8090 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8091 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8092 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8093 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008094};
8095
8096static void calcsize(union node *n);
8097
8098static void
8099sizenodelist(struct nodelist *lp)
8100{
8101 while (lp) {
8102 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8103 calcsize(lp->n);
8104 lp = lp->next;
8105 }
8106}
8107
8108static void
8109calcsize(union node *n)
8110{
8111 if (n == NULL)
8112 return;
8113 funcblocksize += nodesize[n->type];
8114 switch (n->type) {
8115 case NCMD:
8116 calcsize(n->ncmd.redirect);
8117 calcsize(n->ncmd.args);
8118 calcsize(n->ncmd.assign);
8119 break;
8120 case NPIPE:
8121 sizenodelist(n->npipe.cmdlist);
8122 break;
8123 case NREDIR:
8124 case NBACKGND:
8125 case NSUBSHELL:
8126 calcsize(n->nredir.redirect);
8127 calcsize(n->nredir.n);
8128 break;
8129 case NAND:
8130 case NOR:
8131 case NSEMI:
8132 case NWHILE:
8133 case NUNTIL:
8134 calcsize(n->nbinary.ch2);
8135 calcsize(n->nbinary.ch1);
8136 break;
8137 case NIF:
8138 calcsize(n->nif.elsepart);
8139 calcsize(n->nif.ifpart);
8140 calcsize(n->nif.test);
8141 break;
8142 case NFOR:
8143 funcstringsize += strlen(n->nfor.var) + 1;
8144 calcsize(n->nfor.body);
8145 calcsize(n->nfor.args);
8146 break;
8147 case NCASE:
8148 calcsize(n->ncase.cases);
8149 calcsize(n->ncase.expr);
8150 break;
8151 case NCLIST:
8152 calcsize(n->nclist.body);
8153 calcsize(n->nclist.pattern);
8154 calcsize(n->nclist.next);
8155 break;
8156 case NDEFUN:
8157 case NARG:
8158 sizenodelist(n->narg.backquote);
8159 funcstringsize += strlen(n->narg.text) + 1;
8160 calcsize(n->narg.next);
8161 break;
8162 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008163#if ENABLE_ASH_BASH_COMPAT
8164 case NTO2:
8165#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008166 case NCLOBBER:
8167 case NFROM:
8168 case NFROMTO:
8169 case NAPPEND:
8170 calcsize(n->nfile.fname);
8171 calcsize(n->nfile.next);
8172 break;
8173 case NTOFD:
8174 case NFROMFD:
8175 calcsize(n->ndup.vname);
8176 calcsize(n->ndup.next);
8177 break;
8178 case NHERE:
8179 case NXHERE:
8180 calcsize(n->nhere.doc);
8181 calcsize(n->nhere.next);
8182 break;
8183 case NNOT:
8184 calcsize(n->nnot.com);
8185 break;
8186 };
8187}
8188
8189static char *
8190nodeckstrdup(char *s)
8191{
8192 char *rtn = funcstring;
8193
8194 strcpy(funcstring, s);
8195 funcstring += strlen(s) + 1;
8196 return rtn;
8197}
8198
8199static union node *copynode(union node *);
8200
8201static struct nodelist *
8202copynodelist(struct nodelist *lp)
8203{
8204 struct nodelist *start;
8205 struct nodelist **lpp;
8206
8207 lpp = &start;
8208 while (lp) {
8209 *lpp = funcblock;
8210 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8211 (*lpp)->n = copynode(lp->n);
8212 lp = lp->next;
8213 lpp = &(*lpp)->next;
8214 }
8215 *lpp = NULL;
8216 return start;
8217}
8218
8219static union node *
8220copynode(union node *n)
8221{
8222 union node *new;
8223
8224 if (n == NULL)
8225 return NULL;
8226 new = funcblock;
8227 funcblock = (char *) funcblock + nodesize[n->type];
8228
8229 switch (n->type) {
8230 case NCMD:
8231 new->ncmd.redirect = copynode(n->ncmd.redirect);
8232 new->ncmd.args = copynode(n->ncmd.args);
8233 new->ncmd.assign = copynode(n->ncmd.assign);
8234 break;
8235 case NPIPE:
8236 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008237 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008238 break;
8239 case NREDIR:
8240 case NBACKGND:
8241 case NSUBSHELL:
8242 new->nredir.redirect = copynode(n->nredir.redirect);
8243 new->nredir.n = copynode(n->nredir.n);
8244 break;
8245 case NAND:
8246 case NOR:
8247 case NSEMI:
8248 case NWHILE:
8249 case NUNTIL:
8250 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8251 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8252 break;
8253 case NIF:
8254 new->nif.elsepart = copynode(n->nif.elsepart);
8255 new->nif.ifpart = copynode(n->nif.ifpart);
8256 new->nif.test = copynode(n->nif.test);
8257 break;
8258 case NFOR:
8259 new->nfor.var = nodeckstrdup(n->nfor.var);
8260 new->nfor.body = copynode(n->nfor.body);
8261 new->nfor.args = copynode(n->nfor.args);
8262 break;
8263 case NCASE:
8264 new->ncase.cases = copynode(n->ncase.cases);
8265 new->ncase.expr = copynode(n->ncase.expr);
8266 break;
8267 case NCLIST:
8268 new->nclist.body = copynode(n->nclist.body);
8269 new->nclist.pattern = copynode(n->nclist.pattern);
8270 new->nclist.next = copynode(n->nclist.next);
8271 break;
8272 case NDEFUN:
8273 case NARG:
8274 new->narg.backquote = copynodelist(n->narg.backquote);
8275 new->narg.text = nodeckstrdup(n->narg.text);
8276 new->narg.next = copynode(n->narg.next);
8277 break;
8278 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008279#if ENABLE_ASH_BASH_COMPAT
8280 case NTO2:
8281#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008282 case NCLOBBER:
8283 case NFROM:
8284 case NFROMTO:
8285 case NAPPEND:
8286 new->nfile.fname = copynode(n->nfile.fname);
8287 new->nfile.fd = n->nfile.fd;
8288 new->nfile.next = copynode(n->nfile.next);
8289 break;
8290 case NTOFD:
8291 case NFROMFD:
8292 new->ndup.vname = copynode(n->ndup.vname);
8293 new->ndup.dupfd = n->ndup.dupfd;
8294 new->ndup.fd = n->ndup.fd;
8295 new->ndup.next = copynode(n->ndup.next);
8296 break;
8297 case NHERE:
8298 case NXHERE:
8299 new->nhere.doc = copynode(n->nhere.doc);
8300 new->nhere.fd = n->nhere.fd;
8301 new->nhere.next = copynode(n->nhere.next);
8302 break;
8303 case NNOT:
8304 new->nnot.com = copynode(n->nnot.com);
8305 break;
8306 };
8307 new->type = n->type;
8308 return new;
8309}
8310
8311/*
8312 * Make a copy of a parse tree.
8313 */
8314static struct funcnode *
8315copyfunc(union node *n)
8316{
8317 struct funcnode *f;
8318 size_t blocksize;
8319
8320 funcblocksize = offsetof(struct funcnode, n);
8321 funcstringsize = 0;
8322 calcsize(n);
8323 blocksize = funcblocksize;
8324 f = ckmalloc(blocksize + funcstringsize);
8325 funcblock = (char *) f + offsetof(struct funcnode, n);
8326 funcstring = (char *) f + blocksize;
8327 copynode(n);
8328 f->count = 0;
8329 return f;
8330}
8331
8332/*
8333 * Define a shell function.
8334 */
8335static void
8336defun(char *name, union node *func)
8337{
8338 struct cmdentry entry;
8339
8340 INT_OFF;
8341 entry.cmdtype = CMDFUNCTION;
8342 entry.u.func = copyfunc(func);
8343 addcmdentry(name, &entry);
8344 INT_ON;
8345}
8346
Denis Vlasenko4b875702009-03-19 13:30:04 +00008347/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008348#define SKIPBREAK (1 << 0)
8349#define SKIPCONT (1 << 1)
8350#define SKIPFUNC (1 << 2)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008351#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008352static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008353static int skipcount; /* number of levels to skip */
8354static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008355static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008356
Denis Vlasenko4b875702009-03-19 13:30:04 +00008357/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008358static int evalstring(char *s, int mask);
8359
Denis Vlasenko4b875702009-03-19 13:30:04 +00008360/* Called to execute a trap.
8361 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008362 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008363 *
8364 * Perhaps we should avoid entering new trap handlers
8365 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008366 */
8367static int
8368dotrap(void)
8369{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008370 uint8_t *g;
8371 int sig;
8372 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008373
8374 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008375 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008376 xbarrier();
8377
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008378 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008379 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denis Vlasenko4b875702009-03-19 13:30:04 +00008380 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008381
Denis Vlasenko4b875702009-03-19 13:30:04 +00008382 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008383 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008384 t = trap[sig];
8385 /* non-trapped SIGINT is handled separately by raise_interrupt,
8386 * don't upset it by resetting gotsig[SIGINT-1] */
8387 if (sig == SIGINT && !t)
8388 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008389
8390 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008391 *g = 0;
8392 if (!t)
8393 continue;
Denys Vlasenko928e2a72016-09-29 00:30:31 +02008394 evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008395 exitstatus = savestatus;
Denys Vlasenko928e2a72016-09-29 00:30:31 +02008396 if (evalskip) {
8397 TRACE(("dotrap returns %d\n", evalskip));
8398 return evalskip;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008399 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008400 }
8401
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008402 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008403 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008404}
8405
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008406/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008407static int evalloop(union node *, int);
8408static int evalfor(union node *, int);
8409static int evalcase(union node *, int);
8410static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008411static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008412static int evalpipe(union node *, int);
8413static int evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008414static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008415static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008416
Eric Andersen62483552001-07-10 06:09:16 +00008417/*
Eric Andersenc470f442003-07-28 09:56:35 +00008418 * Evaluate a parse tree. The value is left in the global variable
8419 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008420 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008421static int
Eric Andersenc470f442003-07-28 09:56:35 +00008422evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008423{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008424 struct jmploc *volatile savehandler = exception_handler;
8425 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008426 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008427 int (*evalfn)(union node *, int);
8428 int status = 0;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008429 int int_level;
8430
8431 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008432
Eric Andersenc470f442003-07-28 09:56:35 +00008433 if (n == NULL) {
8434 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008435 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008436 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008437 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008438
8439 exception_handler = &jmploc;
8440 {
8441 int err = setjmp(jmploc.loc);
8442 if (err) {
8443 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008444 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008445 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8446 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008447 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008448 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008449 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008450 TRACE(("exception %d in evaltree, propagating err=%d\n",
8451 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008452 exception_handler = savehandler;
8453 longjmp(exception_handler->loc, err);
8454 }
8455 }
8456
Eric Andersenc470f442003-07-28 09:56:35 +00008457 switch (n->type) {
8458 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008459#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008460 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008461 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008462 break;
8463#endif
8464 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008465 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008466 goto setstatus;
8467 case NREDIR:
8468 expredir(n->nredir.redirect);
8469 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8470 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008471 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008472 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008473 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008474 goto setstatus;
8475 case NCMD:
8476 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008477 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008478 if (eflag && !(flags & EV_TESTED))
8479 checkexit = ~0;
8480 goto calleval;
8481 case NFOR:
8482 evalfn = evalfor;
8483 goto calleval;
8484 case NWHILE:
8485 case NUNTIL:
8486 evalfn = evalloop;
8487 goto calleval;
8488 case NSUBSHELL:
Rostislav Skudnov204c7fb2016-09-16 19:04:02 +00008489 evalfn = evalsubshell;
8490 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008491 case NBACKGND:
8492 evalfn = evalsubshell;
8493 goto calleval;
8494 case NPIPE:
8495 evalfn = evalpipe;
8496 goto checkexit;
8497 case NCASE:
8498 evalfn = evalcase;
8499 goto calleval;
8500 case NAND:
8501 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008502 case NSEMI: {
8503
Eric Andersenc470f442003-07-28 09:56:35 +00008504#if NAND + 1 != NOR
8505#error NAND + 1 != NOR
8506#endif
8507#if NOR + 1 != NSEMI
8508#error NOR + 1 != NSEMI
8509#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008510 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008511 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008512 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008513 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008514 );
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008515 if (!status == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008516 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008517 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008518 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008519 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008520 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008521 status = evalfn(n, flags);
8522 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008523 }
Eric Andersenc470f442003-07-28 09:56:35 +00008524 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008525 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008526 if (evalskip)
8527 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008528 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008529 n = n->nif.ifpart;
8530 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008531 }
8532 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008533 n = n->nif.elsepart;
8534 goto evaln;
8535 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008536 status = 0;
8537 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008538 case NDEFUN:
8539 defun(n->narg.text, n->narg.next);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008540 /* Not necessary. To test it:
8541 * "false; f() { qwerty; }; echo $?" should print 0.
8542 */
8543 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008544 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008545 exitstatus = status;
8546 break;
8547 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008548
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008549 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008550 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008551
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008552 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008553 /* Order of checks below is important:
8554 * signal handlers trigger before exit caused by "set -e".
8555 */
8556 if (pending_sig && dotrap())
8557 goto exexit;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008558 if (checkexit & status)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008559 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008560
8561 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008562 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008563 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008564 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008565
8566 RESTORE_INT(int_level);
8567 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008568
8569 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008570}
8571
Eric Andersenc470f442003-07-28 09:56:35 +00008572#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8573static
8574#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008575int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008576
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008577static int
Eric Andersenc470f442003-07-28 09:56:35 +00008578evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008579{
8580 int status;
8581
8582 loopnest++;
8583 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008584 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008585 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008586 int i;
8587
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008588 i = evaltree(n->nbinary.ch1, EV_TESTED);
Eric Andersencb57d552001-06-28 07:25:16 +00008589 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008590 skipping:
8591 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008592 evalskip = 0;
8593 continue;
8594 }
8595 if (evalskip == SKIPBREAK && --skipcount <= 0)
8596 evalskip = 0;
8597 break;
8598 }
Eric Andersenc470f442003-07-28 09:56:35 +00008599 if (n->type != NWHILE)
8600 i = !i;
8601 if (i != 0)
8602 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008603 status = evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008604 if (evalskip)
8605 goto skipping;
8606 }
Eric Andersencb57d552001-06-28 07:25:16 +00008607 exitstatus = status;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008608 loopnest--;
8609
8610 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008611}
8612
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008613static int
Eric Andersenc470f442003-07-28 09:56:35 +00008614evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008615{
8616 struct arglist arglist;
8617 union node *argp;
8618 struct strlist *sp;
8619 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008620 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008621
8622 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008623 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008624 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008625 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008626 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008627 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008628 if (evalskip)
8629 goto out;
8630 }
8631 *arglist.lastp = NULL;
8632
Eric Andersencb57d552001-06-28 07:25:16 +00008633 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008634 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008635 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008636 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008637 status = evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008638 if (evalskip) {
8639 if (evalskip == SKIPCONT && --skipcount <= 0) {
8640 evalskip = 0;
8641 continue;
8642 }
8643 if (evalskip == SKIPBREAK && --skipcount <= 0)
8644 evalskip = 0;
8645 break;
8646 }
8647 }
8648 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008649 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008650 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008651
8652 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008653}
8654
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008655static int
Eric Andersenc470f442003-07-28 09:56:35 +00008656evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008657{
8658 union node *cp;
8659 union node *patp;
8660 struct arglist arglist;
8661 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008662 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008663
8664 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008665 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008666 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008667 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008668 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8669 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008670 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008671 /* Ensure body is non-empty as otherwise
8672 * EV_EXIT may prevent us from setting the
8673 * exit status.
8674 */
8675 if (evalskip == 0 && cp->nclist.body) {
8676 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008677 }
8678 goto out;
8679 }
8680 }
8681 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008682 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008683 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008684
8685 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008686}
8687
Eric Andersenc470f442003-07-28 09:56:35 +00008688/*
8689 * Kick off a subshell to evaluate a tree.
8690 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008691static int
Eric Andersenc470f442003-07-28 09:56:35 +00008692evalsubshell(union node *n, int flags)
8693{
8694 struct job *jp;
8695 int backgnd = (n->type == NBACKGND);
8696 int status;
8697
8698 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008699 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008700 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008701 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008702 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008703 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008704 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008705 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008706 flags |= EV_EXIT;
8707 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008708 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008709 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008710 redirect(n->nredir.redirect, 0);
8711 evaltreenr(n->nredir.n, flags);
8712 /* never returns */
8713 }
8714 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008715 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008716 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008717 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008718 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008719}
8720
Eric Andersenc470f442003-07-28 09:56:35 +00008721/*
8722 * Compute the names of the files in a redirection list.
8723 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008724static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008725static void
8726expredir(union node *n)
8727{
8728 union node *redir;
8729
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008730 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008731 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008732
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008733 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008734 fn.lastp = &fn.list;
8735 switch (redir->type) {
8736 case NFROMTO:
8737 case NFROM:
8738 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008739#if ENABLE_ASH_BASH_COMPAT
8740 case NTO2:
8741#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008742 case NCLOBBER:
8743 case NAPPEND:
8744 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008745 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008746#if ENABLE_ASH_BASH_COMPAT
8747 store_expfname:
8748#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008749#if 0
8750// By the design of stack allocator, the loop of this kind:
8751// while true; do while true; do break; done </dev/null; done
8752// will look like a memory leak: ash plans to free expfname's
8753// of "/dev/null" as soon as it finishes running the loop
8754// (in this case, never).
8755// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008756 if (redir->nfile.expfname)
8757 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008758// It results in corrupted state of stacked allocations.
8759#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008760 redir->nfile.expfname = fn.list->text;
8761 break;
8762 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008763 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008764 if (redir->ndup.vname) {
8765 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008766 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008767 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008768#if ENABLE_ASH_BASH_COMPAT
8769//FIXME: we used expandarg with different args!
8770 if (!isdigit_str9(fn.list->text)) {
8771 /* >&file, not >&fd */
8772 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8773 ash_msg_and_raise_error("redir error");
8774 redir->type = NTO2;
8775 goto store_expfname;
8776 }
8777#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008778 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008779 }
8780 break;
8781 }
8782 }
8783}
8784
Eric Andersencb57d552001-06-28 07:25:16 +00008785/*
Eric Andersencb57d552001-06-28 07:25:16 +00008786 * Evaluate a pipeline. All the processes in the pipeline are children
8787 * of the process creating the pipeline. (This differs from some versions
8788 * of the shell, which make the last process in a pipeline the parent
8789 * of all the rest.)
8790 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008791static int
Eric Andersenc470f442003-07-28 09:56:35 +00008792evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008793{
8794 struct job *jp;
8795 struct nodelist *lp;
8796 int pipelen;
8797 int prevfd;
8798 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008799 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008800
Eric Andersenc470f442003-07-28 09:56:35 +00008801 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008802 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008803 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008804 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008805 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008806 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008807 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008808 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008809 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008810 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008811 pip[1] = -1;
8812 if (lp->next) {
8813 if (pipe(pip) < 0) {
8814 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008815 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008816 }
8817 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008818 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008819 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008820 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008821 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008822 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008823 if (prevfd > 0) {
8824 dup2(prevfd, 0);
8825 close(prevfd);
8826 }
8827 if (pip[1] > 1) {
8828 dup2(pip[1], 1);
8829 close(pip[1]);
8830 }
Eric Andersenc470f442003-07-28 09:56:35 +00008831 evaltreenr(lp->n, flags);
8832 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008833 }
8834 if (prevfd >= 0)
8835 close(prevfd);
8836 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008837 /* Don't want to trigger debugging */
8838 if (pip[1] != -1)
8839 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008840 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008841 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008842 status = waitforjob(jp);
8843 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008844 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008845 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008846
8847 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008848}
8849
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008850/*
8851 * Controls whether the shell is interactive or not.
8852 */
8853static void
8854setinteractive(int on)
8855{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008856 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008857
8858 if (++on == is_interactive)
8859 return;
8860 is_interactive = on;
8861 setsignal(SIGINT);
8862 setsignal(SIGQUIT);
8863 setsignal(SIGTERM);
8864#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8865 if (is_interactive > 1) {
8866 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008867 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008868
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008869 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008870 /* note: ash and hush share this string */
8871 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008872 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8873 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008874 bb_banner,
8875 "built-in shell (ash)"
8876 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008877 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008878 }
8879 }
8880#endif
8881}
8882
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008883static void
8884optschanged(void)
8885{
8886#if DEBUG
8887 opentrace();
8888#endif
8889 setinteractive(iflag);
8890 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008891#if ENABLE_FEATURE_EDITING_VI
8892 if (viflag)
8893 line_input_state->flags |= VI_MODE;
8894 else
8895 line_input_state->flags &= ~VI_MODE;
8896#else
8897 viflag = 0; /* forcibly keep the option off */
8898#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008899}
8900
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008901static struct localvar *localvars;
8902
8903/*
8904 * Called after a function returns.
8905 * Interrupts must be off.
8906 */
8907static void
8908poplocalvars(void)
8909{
8910 struct localvar *lvp;
8911 struct var *vp;
8912
8913 while ((lvp = localvars) != NULL) {
8914 localvars = lvp->next;
8915 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008916 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008917 if (vp == NULL) { /* $- saved */
8918 memcpy(optlist, lvp->text, sizeof(optlist));
8919 free((char*)lvp->text);
8920 optschanged();
8921 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008922 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008923 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008924 if (vp->var_func)
8925 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008926 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008927 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008928 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008929 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008930 }
8931 free(lvp);
8932 }
8933}
8934
8935static int
8936evalfun(struct funcnode *func, int argc, char **argv, int flags)
8937{
8938 volatile struct shparam saveparam;
8939 struct localvar *volatile savelocalvars;
8940 struct jmploc *volatile savehandler;
8941 struct jmploc jmploc;
8942 int e;
8943
8944 saveparam = shellparam;
8945 savelocalvars = localvars;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02008946 savehandler = exception_handler;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008947 e = setjmp(jmploc.loc);
8948 if (e) {
8949 goto funcdone;
8950 }
8951 INT_OFF;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008952 exception_handler = &jmploc;
8953 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008954 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008955 func->count++;
8956 funcnest++;
8957 INT_ON;
8958 shellparam.nparam = argc - 1;
8959 shellparam.p = argv + 1;
8960#if ENABLE_ASH_GETOPTS
8961 shellparam.optind = 1;
8962 shellparam.optoff = -1;
8963#endif
8964 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008965 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008966 INT_OFF;
8967 funcnest--;
8968 freefunc(func);
8969 poplocalvars();
8970 localvars = savelocalvars;
8971 freeparam(&shellparam);
8972 shellparam = saveparam;
8973 exception_handler = savehandler;
8974 INT_ON;
8975 evalskip &= ~SKIPFUNC;
8976 return e;
8977}
8978
Denis Vlasenko131ae172007-02-18 13:00:19 +00008979#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008980static char **
8981parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008982{
8983 char *cp, c;
8984
8985 for (;;) {
8986 cp = *++argv;
8987 if (!cp)
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008988 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008989 if (*cp++ != '-')
8990 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008991 c = *cp++;
8992 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008993 break;
8994 if (c == '-' && !*cp) {
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008995 if (!*++argv)
8996 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008997 break;
8998 }
8999 do {
9000 switch (c) {
9001 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00009002 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00009003 break;
9004 default:
9005 /* run 'typecmd' for other options */
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01009006 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009007 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00009008 c = *cp++;
9009 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00009010 }
9011 return argv;
9012}
9013#endif
9014
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009015/*
9016 * Make a variable a local variable. When a variable is made local, it's
9017 * value and flags are saved in a localvar structure. The saved values
9018 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009019 * "-" as a special case: it makes changes to "set +-options" local
9020 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009021 */
9022static void
9023mklocal(char *name)
9024{
9025 struct localvar *lvp;
9026 struct var **vpp;
9027 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009028 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009029
9030 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009031 /* Cater for duplicate "local". Examples:
9032 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9033 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9034 */
9035 lvp = localvars;
9036 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009037 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009038 if (eq)
9039 setvareq(name, 0);
9040 /* else:
9041 * it's a duplicate "local VAR" declaration, do nothing
9042 */
9043 return;
9044 }
9045 lvp = lvp->next;
9046 }
9047
9048 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009049 if (LONE_DASH(name)) {
9050 char *p;
9051 p = ckmalloc(sizeof(optlist));
9052 lvp->text = memcpy(p, optlist, sizeof(optlist));
9053 vp = NULL;
9054 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009055 vpp = hashvar(name);
9056 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009057 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009058 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009059 if (eq)
9060 setvareq(name, VSTRFIXED);
9061 else
9062 setvar(name, NULL, VSTRFIXED);
9063 vp = *vpp; /* the new variable */
9064 lvp->flags = VUNSET;
9065 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009066 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009067 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009068 /* make sure neither "struct var" nor string gets freed
9069 * during (un)setting:
9070 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009071 vp->flags |= VSTRFIXED|VTEXTFIXED;
9072 if (eq)
9073 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009074 else
9075 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009076 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009077 }
9078 }
9079 lvp->vp = vp;
9080 lvp->next = localvars;
9081 localvars = lvp;
9082 INT_ON;
9083}
9084
9085/*
9086 * The "local" command.
9087 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009088static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009089localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009090{
9091 char *name;
9092
Ron Yorstonef2386b2015-10-29 16:19:14 +00009093 if (!funcnest)
9094 ash_msg_and_raise_error("not in a function");
9095
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009096 argv = argptr;
9097 while ((name = *argv++) != NULL) {
9098 mklocal(name);
9099 }
9100 return 0;
9101}
9102
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009103static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009104falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009105{
9106 return 1;
9107}
9108
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009109static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009110truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009111{
9112 return 0;
9113}
9114
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009115static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009116execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009117{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009118 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009119 iflag = 0; /* exit on error */
9120 mflag = 0;
9121 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009122 /* We should set up signals for "exec CMD"
9123 * the same way as for "CMD" without "exec".
9124 * But optschanged->setinteractive->setsignal
9125 * still thought we are a root shell. Therefore, for example,
9126 * SIGQUIT is still set to IGN. Fix it:
9127 */
9128 shlvl++;
9129 setsignal(SIGQUIT);
9130 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9131 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9132 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9133
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009134 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009135 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009136 }
9137 return 0;
9138}
9139
9140/*
9141 * The return command.
9142 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009143static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009144returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009145{
9146 /*
9147 * If called outside a function, do what ksh does;
9148 * skip the rest of the file.
9149 */
Denys Vlasenko6a0710e2016-09-30 14:18:34 +02009150 evalskip = SKIPFUNC;
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009151 return argv[1] ? number(argv[1]) : exitstatus;
9152}
9153
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009154/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009155static int breakcmd(int, char **) FAST_FUNC;
9156static int dotcmd(int, char **) FAST_FUNC;
9157static int evalcmd(int, char **) FAST_FUNC;
9158static int exitcmd(int, char **) FAST_FUNC;
9159static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009160#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009161static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009162#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009163#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009164static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009165#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009166#if MAX_HISTORY
9167static int historycmd(int, char **) FAST_FUNC;
9168#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009169#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009170static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009171#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009172static int readcmd(int, char **) FAST_FUNC;
9173static int setcmd(int, char **) FAST_FUNC;
9174static int shiftcmd(int, char **) FAST_FUNC;
9175static int timescmd(int, char **) FAST_FUNC;
9176static int trapcmd(int, char **) FAST_FUNC;
9177static int umaskcmd(int, char **) FAST_FUNC;
9178static int unsetcmd(int, char **) FAST_FUNC;
9179static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009180
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009181#define BUILTIN_NOSPEC "0"
9182#define BUILTIN_SPECIAL "1"
9183#define BUILTIN_REGULAR "2"
9184#define BUILTIN_SPEC_REG "3"
9185#define BUILTIN_ASSIGN "4"
9186#define BUILTIN_SPEC_ASSG "5"
9187#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009188#define BUILTIN_SPEC_REG_ASSG "7"
9189
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009190/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009191#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009192static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009193#endif
9194#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009195static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009196#endif
9197#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009198static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009199#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009200
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009201/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009202static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009203 { BUILTIN_SPEC_REG "." , dotcmd },
9204 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009205#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009206 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009207#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009208 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009209#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009210#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009211#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009212 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009213#endif
9214#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009215 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009216#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009217 { BUILTIN_SPEC_REG "break" , breakcmd },
9218 { BUILTIN_REGULAR "cd" , cdcmd },
9219 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009220#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009221 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009222#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009223 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009224#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009225 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009226#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009227 { BUILTIN_SPEC_REG "eval" , evalcmd },
9228 { BUILTIN_SPEC_REG "exec" , execcmd },
9229 { BUILTIN_SPEC_REG "exit" , exitcmd },
9230 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9231 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009232#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009233 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009234#endif
9235#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009236 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009237#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009238 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009239#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009240 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009241#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009242#if MAX_HISTORY
9243 { BUILTIN_NOSPEC "history" , historycmd },
9244#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009245#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009246 { BUILTIN_REGULAR "jobs" , jobscmd },
9247 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009248#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009249#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009250 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009251#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009252 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009253#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009254 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009255#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009256 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9257 { BUILTIN_REGULAR "read" , readcmd },
9258 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9259 { BUILTIN_SPEC_REG "return" , returncmd },
9260 { BUILTIN_SPEC_REG "set" , setcmd },
9261 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009262#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009263 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009264#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009265#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009266 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009267#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009268 { BUILTIN_SPEC_REG "times" , timescmd },
9269 { BUILTIN_SPEC_REG "trap" , trapcmd },
9270 { BUILTIN_REGULAR "true" , truecmd },
9271 { BUILTIN_NOSPEC "type" , typecmd },
9272 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9273 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009274#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009275 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009276#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009277 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9278 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009279};
9280
Denis Vlasenko80591b02008-03-25 07:49:43 +00009281/* Should match the above table! */
9282#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009283 /* . : */ 2 + \
9284 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9285 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9286 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9287 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9288 /* break cd cddir */ 3)
9289#define EVALCMD (COMMANDCMD + \
9290 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9291 /* continue */ 1 + \
9292 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9293 0)
9294#define EXECCMD (EVALCMD + \
9295 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009296
9297/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009298 * Search the table of builtin commands.
9299 */
9300static struct builtincmd *
9301find_builtin(const char *name)
9302{
9303 struct builtincmd *bp;
9304
9305 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009306 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009307 pstrcmp
9308 );
9309 return bp;
9310}
9311
9312/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009313 * Execute a simple command.
9314 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009315static int
9316isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009317{
9318 const char *q = endofname(p);
9319 if (p == q)
9320 return 0;
9321 return *q == '=';
9322}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009323static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009324bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009325{
9326 /* Preserve exitstatus of a previous possible redirection
9327 * as POSIX mandates */
9328 return back_exitstatus;
9329}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009330static int
Eric Andersenc470f442003-07-28 09:56:35 +00009331evalcommand(union node *cmd, int flags)
9332{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009333 static const struct builtincmd null_bltin = {
9334 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009335 };
Eric Andersenc470f442003-07-28 09:56:35 +00009336 struct stackmark smark;
9337 union node *argp;
9338 struct arglist arglist;
9339 struct arglist varlist;
9340 char **argv;
9341 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009342 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009343 struct cmdentry cmdentry;
9344 struct job *jp;
9345 char *lastarg;
9346 const char *path;
9347 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009348 int status;
9349 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009350 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009351 smallint cmd_is_exec;
9352 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009353
9354 /* First expand the arguments. */
9355 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9356 setstackmark(&smark);
9357 back_exitstatus = 0;
9358
9359 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009360 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009361 varlist.lastp = &varlist.list;
9362 *varlist.lastp = NULL;
9363 arglist.lastp = &arglist.list;
9364 *arglist.lastp = NULL;
9365
9366 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009367 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009368 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9369 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9370 }
9371
Eric Andersenc470f442003-07-28 09:56:35 +00009372 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9373 struct strlist **spp;
9374
9375 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009376 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009377 expandarg(argp, &arglist, EXP_VARTILDE);
9378 else
9379 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9380
Eric Andersenc470f442003-07-28 09:56:35 +00009381 for (sp = *spp; sp; sp = sp->next)
9382 argc++;
9383 }
9384
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009385 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009386 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009387 TRACE(("evalcommand arg: %s\n", sp->text));
9388 *nargv++ = sp->text;
9389 }
9390 *nargv = NULL;
9391
9392 lastarg = NULL;
9393 if (iflag && funcnest == 0 && argc > 0)
9394 lastarg = nargv[-1];
9395
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009396 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009397 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009398 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009399
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009400 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009401 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9402 struct strlist **spp;
9403 char *p;
9404
9405 spp = varlist.lastp;
9406 expandarg(argp, &varlist, EXP_VARTILDE);
9407
9408 /*
9409 * Modify the command lookup path, if a PATH= assignment
9410 * is present
9411 */
9412 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009413 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009414 path = p;
9415 }
9416
9417 /* Print the command if xflag is set. */
9418 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009419 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009420 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009421
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009422 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009423 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009424 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009425 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009426 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009427 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009428 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009429 }
9430 sp = arglist.list;
9431 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009432 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009433 }
9434
9435 cmd_is_exec = 0;
9436 spclbltin = -1;
9437
9438 /* Now locate the command. */
9439 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009440 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009441#if ENABLE_ASH_CMDCMD
9442 const char *oldpath = path + 5;
9443#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009444 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009445 for (;;) {
9446 find_command(argv[0], &cmdentry, cmd_flag, path);
9447 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009448 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009449 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009450 goto bail;
9451 }
9452
9453 /* implement bltin and command here */
9454 if (cmdentry.cmdtype != CMDBUILTIN)
9455 break;
9456 if (spclbltin < 0)
9457 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9458 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009459 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009460#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009461 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009462 path = oldpath;
9463 nargv = parse_command_args(argv, &path);
9464 if (!nargv)
9465 break;
9466 argc -= nargv - argv;
9467 argv = nargv;
9468 cmd_flag |= DO_NOFUNC;
9469 } else
9470#endif
9471 break;
9472 }
9473 }
9474
9475 if (status) {
9476 /* We have a redirection error. */
9477 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009478 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009479 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009480 exitstatus = status;
9481 goto out;
9482 }
9483
9484 /* Execute the command. */
9485 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009486 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009487
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009488#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009489/* (1) BUG: if variables are set, we need to fork, or save/restore them
9490 * around run_nofork_applet() call.
9491 * (2) Should this check also be done in forkshell()?
9492 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9493 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009494 /* find_command() encodes applet_no as (-2 - applet_no) */
9495 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009496 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009497 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009498 /* run <applet>_main() */
9499 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009500 break;
9501 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009502#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009503 /* Can we avoid forking off? For example, very last command
9504 * in a script or a subshell does not need forking,
9505 * we can just exec it.
9506 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009507 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009508 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009509 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009510 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009511 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009512 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009513 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009514 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009515 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009516 break;
9517 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009518 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009519 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009520 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009521 }
9522 listsetvar(varlist.list, VEXPORT|VSTACK);
9523 shellexec(argv, path, cmdentry.u.index);
9524 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009525 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009526 case CMDBUILTIN:
9527 cmdenviron = varlist.list;
9528 if (cmdenviron) {
9529 struct strlist *list = cmdenviron;
9530 int i = VNOSET;
9531 if (spclbltin > 0 || argc == 0) {
9532 i = 0;
9533 if (cmd_is_exec && argc > 1)
9534 i = VEXPORT;
9535 }
9536 listsetvar(list, i);
9537 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009538 /* Tight loop with builtins only:
9539 * "while kill -0 $child; do true; done"
9540 * will never exit even if $child died, unless we do this
9541 * to reap the zombie and make kill detect that it's gone: */
9542 dowait(DOWAIT_NONBLOCK, NULL);
9543
Eric Andersenc470f442003-07-28 09:56:35 +00009544 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9545 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009546 int i = exception_type;
Ron Yorston8c55dc72015-10-30 19:06:47 +00009547 if (i == EXEXIT || i == EXEXEC)
Eric Andersenc470f442003-07-28 09:56:35 +00009548 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009549 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009550 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009551 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009552 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009553 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009554 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009555 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009556 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009557 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009558 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009559 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009560 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009561 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009562
9563 case CMDFUNCTION:
9564 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009565 /* See above for the rationale */
9566 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009567 if (evalfun(cmdentry.u.func, argc, argv, flags))
9568 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009569 readstatus:
9570 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009571 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009572 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009573
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009574 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009575 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009576 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009577 /* dsl: I think this is intended to be used to support
9578 * '_' in 'vi' command mode during line editing...
9579 * However I implemented that within libedit itself.
9580 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009581 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009582 }
Eric Andersenc470f442003-07-28 09:56:35 +00009583 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009584
9585 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009586}
9587
9588static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009589evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9590{
Eric Andersenc470f442003-07-28 09:56:35 +00009591 char *volatile savecmdname;
9592 struct jmploc *volatile savehandler;
9593 struct jmploc jmploc;
9594 int i;
9595
9596 savecmdname = commandname;
Denys Vlasenkoa2d121c2016-09-30 11:30:11 +02009597 savehandler = exception_handler;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009598 i = setjmp(jmploc.loc);
9599 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009600 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009601 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009602 commandname = argv[0];
9603 argptr = argv + 1;
9604 optptr = NULL; /* initialize nextopt */
9605 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009606 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009607 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009608 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009609 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009610 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009611 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009612
9613 return i;
9614}
9615
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009616static int
9617goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009618{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009619 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009620}
9621
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009622
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009623/*
9624 * Search for a command. This is called before we fork so that the
9625 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009626 * the child. The check for "goodname" is an overly conservative
9627 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009628 */
Eric Andersenc470f442003-07-28 09:56:35 +00009629static void
9630prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009631{
9632 struct cmdentry entry;
9633
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009634 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9635 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009636}
9637
Eric Andersencb57d552001-06-28 07:25:16 +00009638
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009639/* ============ Builtin commands
9640 *
9641 * Builtin commands whose functions are closely tied to evaluation
9642 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009643 */
9644
9645/*
Eric Andersencb57d552001-06-28 07:25:16 +00009646 * Handle break and continue commands. Break, continue, and return are
9647 * all handled by setting the evalskip flag. The evaluation routines
9648 * above all check this flag, and if it is set they start skipping
9649 * commands rather than executing them. The variable skipcount is
9650 * the number of loops to break/continue, or the number of function
9651 * levels to return. (The latter is always 1.) It should probably
9652 * be an error to break out of more loops than exist, but it isn't
9653 * in the standard shell so we don't make it one here.
9654 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009655static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009656breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009657{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009658 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009659
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009660 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009661 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009662 if (n > loopnest)
9663 n = loopnest;
9664 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009665 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009666 skipcount = n;
9667 }
9668 return 0;
9669}
9670
Eric Andersenc470f442003-07-28 09:56:35 +00009671
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009672/* ============ input.c
9673 *
Eric Andersen90898442003-08-06 11:20:52 +00009674 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009675 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009676
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009677enum {
9678 INPUT_PUSH_FILE = 1,
9679 INPUT_NOFILE_OK = 2,
9680};
Eric Andersencb57d552001-06-28 07:25:16 +00009681
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009682static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009683/* values of checkkwd variable */
9684#define CHKALIAS 0x1
9685#define CHKKWD 0x2
9686#define CHKNL 0x4
9687
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009688/*
9689 * Push a string back onto the input at this current parsefile level.
9690 * We handle aliases this way.
9691 */
9692#if !ENABLE_ASH_ALIAS
9693#define pushstring(s, ap) pushstring(s)
9694#endif
9695static void
9696pushstring(char *s, struct alias *ap)
9697{
9698 struct strpush *sp;
9699 int len;
9700
9701 len = strlen(s);
9702 INT_OFF;
9703 if (g_parsefile->strpush) {
9704 sp = ckzalloc(sizeof(*sp));
9705 sp->prev = g_parsefile->strpush;
9706 } else {
9707 sp = &(g_parsefile->basestrpush);
9708 }
9709 g_parsefile->strpush = sp;
9710 sp->prev_string = g_parsefile->next_to_pgetc;
9711 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009712 sp->unget = g_parsefile->unget;
9713 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009714#if ENABLE_ASH_ALIAS
9715 sp->ap = ap;
9716 if (ap) {
9717 ap->flag |= ALIASINUSE;
9718 sp->string = s;
9719 }
9720#endif
9721 g_parsefile->next_to_pgetc = s;
9722 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009723 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009724 INT_ON;
9725}
9726
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009727static void
9728popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009729{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009730 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009731
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009732 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009733#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009734 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009735 if (g_parsefile->next_to_pgetc[-1] == ' '
9736 || g_parsefile->next_to_pgetc[-1] == '\t'
9737 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009738 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009739 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009740 if (sp->string != sp->ap->val) {
9741 free(sp->string);
9742 }
9743 sp->ap->flag &= ~ALIASINUSE;
9744 if (sp->ap->flag & ALIASDEAD) {
9745 unalias(sp->ap->name);
9746 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009747 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009748#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009749 g_parsefile->next_to_pgetc = sp->prev_string;
9750 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009751 g_parsefile->unget = sp->unget;
9752 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009753 g_parsefile->strpush = sp->prev;
9754 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009755 free(sp);
9756 INT_ON;
9757}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009758
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009759static int
9760preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009761{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009762 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009763 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009764
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009765 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009766#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009767 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009768 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009769 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009770 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009771 int timeout = -1;
9772# if ENABLE_ASH_IDLE_TIMEOUT
9773 if (iflag) {
9774 const char *tmout_var = lookupvar("TMOUT");
9775 if (tmout_var) {
9776 timeout = atoi(tmout_var) * 1000;
9777 if (timeout <= 0)
9778 timeout = -1;
9779 }
9780 }
9781# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009782# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009783 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009784# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009785 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009786 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009787 if (nr == 0) {
9788 /* Ctrl+C pressed */
9789 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009790 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009791 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009792 raise(SIGINT);
9793 return 1;
9794 }
Eric Andersenc470f442003-07-28 09:56:35 +00009795 goto retry;
9796 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009797 if (nr < 0) {
9798 if (errno == 0) {
9799 /* Ctrl+D pressed */
9800 nr = 0;
9801 }
9802# if ENABLE_ASH_IDLE_TIMEOUT
9803 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009804 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009805 exitshell();
9806 }
9807# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009808 }
Eric Andersencb57d552001-06-28 07:25:16 +00009809 }
9810#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009811 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009812#endif
9813
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009814#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009815 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009816 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009817 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009818 if (flags >= 0 && (flags & O_NONBLOCK)) {
9819 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009820 if (fcntl(0, F_SETFL, flags) >= 0) {
9821 out2str("sh: turning off NDELAY mode\n");
9822 goto retry;
9823 }
9824 }
9825 }
9826 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009827#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009828 return nr;
9829}
9830
9831/*
9832 * Refill the input buffer and return the next input character:
9833 *
9834 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009835 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9836 * or we are reading from a string so we can't refill the buffer,
9837 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009838 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009839 * 4) Process input up to the next newline, deleting nul characters.
9840 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009841//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9842#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009843static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009844static int
Eric Andersenc470f442003-07-28 09:56:35 +00009845preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009846{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009847 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009848 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009849
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009850 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009851#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009852 if (g_parsefile->left_in_line == -1
9853 && g_parsefile->strpush->ap
9854 && g_parsefile->next_to_pgetc[-1] != ' '
9855 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009856 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009857 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009858 return PEOA;
9859 }
Eric Andersen2870d962001-07-02 17:27:21 +00009860#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009861 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009862 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009863 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009864 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009865 * "pgetc" needs refilling.
9866 */
9867
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009868 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009869 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009870 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009871 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009872 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009873 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009874 /* even in failure keep left_in_line and next_to_pgetc
9875 * in lock step, for correct multi-layer pungetc.
9876 * left_in_line was decremented before preadbuffer(),
9877 * must inc next_to_pgetc: */
9878 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009879 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009880 }
Eric Andersencb57d552001-06-28 07:25:16 +00009881
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009882 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009883 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009884 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009885 again:
9886 more = preadfd();
9887 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009888 /* don't try reading again */
9889 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009890 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009891 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009892 return PEOF;
9893 }
9894 }
9895
Denis Vlasenko727752d2008-11-28 03:41:47 +00009896 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009897 * Set g_parsefile->left_in_line
9898 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009899 * NUL chars are deleted.
9900 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009901 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009902 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009903 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009904
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009905 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009906
Denis Vlasenko727752d2008-11-28 03:41:47 +00009907 c = *q;
9908 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009909 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009910 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009911 q++;
9912 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009913 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009914 break;
9915 }
Eric Andersencb57d552001-06-28 07:25:16 +00009916 }
9917
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009918 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009919 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9920 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009921 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009922 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009923 }
9924 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009925 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009926
Eric Andersencb57d552001-06-28 07:25:16 +00009927 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009928 char save = *q;
9929 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009930 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009931 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009932 }
9933
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009934 pgetc_debug("preadbuffer at %d:%p'%s'",
9935 g_parsefile->left_in_line,
9936 g_parsefile->next_to_pgetc,
9937 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009938 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009939}
9940
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009941static int
9942pgetc(void)
9943{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009944 int c;
9945
9946 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009947 g_parsefile->left_in_line,
9948 g_parsefile->next_to_pgetc,
9949 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009950 if (g_parsefile->unget)
9951 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009952
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009953 if (--g_parsefile->left_in_line >= 0)
9954 c = (signed char)*g_parsefile->next_to_pgetc++;
9955 else
9956 c = preadbuffer();
9957
9958 g_parsefile->lastc[1] = g_parsefile->lastc[0];
9959 g_parsefile->lastc[0] = c;
9960
9961 return c;
9962}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009963
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009964#if ENABLE_ASH_ALIAS
9965static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009966pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009967{
9968 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009969 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009970 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009971 g_parsefile->left_in_line,
9972 g_parsefile->next_to_pgetc,
9973 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009974 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009975 } while (c == PEOA);
9976 return c;
9977}
9978#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009979# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009980#endif
9981
9982/*
9983 * Read a line from the script.
9984 */
9985static char *
9986pfgets(char *line, int len)
9987{
9988 char *p = line;
9989 int nleft = len;
9990 int c;
9991
9992 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009993 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009994 if (c == PEOF) {
9995 if (p == line)
9996 return NULL;
9997 break;
9998 }
9999 *p++ = c;
10000 if (c == '\n')
10001 break;
10002 }
10003 *p = '\0';
10004 return line;
10005}
10006
Eric Andersenc470f442003-07-28 09:56:35 +000010007/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010008 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010009 * PEOF may be pushed back.
10010 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010011static void
Eric Andersenc470f442003-07-28 09:56:35 +000010012pungetc(void)
10013{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010014 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010015}
10016
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010017/* This one eats backslash+newline */
10018static int
10019pgetc_eatbnl(void)
10020{
10021 int c;
10022
10023 while ((c = pgetc()) == '\\') {
10024 if (pgetc() != '\n') {
10025 pungetc();
10026 break;
10027 }
10028
10029 g_parsefile->linno++;
10030 setprompt_if(doprompt, 2);
10031 }
10032
10033 return c;
10034}
10035
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010036/*
10037 * To handle the "." command, a stack of input files is used. Pushfile
10038 * adds a new entry to the stack and popfile restores the previous level.
10039 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010040static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010041pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010042{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010043 struct parsefile *pf;
10044
Denis Vlasenko597906c2008-02-20 16:38:54 +000010045 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010046 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010047 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010048 /*pf->strpush = NULL; - ckzalloc did it */
10049 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010050 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010051 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010052}
10053
10054static void
10055popfile(void)
10056{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010057 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010058
Denis Vlasenkob012b102007-02-19 22:43:01 +000010059 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010060 if (pf->pf_fd >= 0)
10061 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010062 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010063 while (pf->strpush)
10064 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010065 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010066 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010067 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010068}
10069
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010070/*
10071 * Return to top level.
10072 */
10073static void
10074popallfiles(void)
10075{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010076 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010077 popfile();
10078}
10079
10080/*
10081 * Close the file(s) that the shell is reading commands from. Called
10082 * after a fork is done.
10083 */
10084static void
10085closescript(void)
10086{
10087 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010088 if (g_parsefile->pf_fd > 0) {
10089 close(g_parsefile->pf_fd);
10090 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010091 }
10092}
10093
10094/*
10095 * Like setinputfile, but takes an open file descriptor. Call this with
10096 * interrupts off.
10097 */
10098static void
10099setinputfd(int fd, int push)
10100{
Denis Vlasenko96e1b382007-09-30 23:50:48 +000010101 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010102 if (push) {
10103 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010104 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010105 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010106 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010107 if (g_parsefile->buf == NULL)
10108 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010109 g_parsefile->left_in_buffer = 0;
10110 g_parsefile->left_in_line = 0;
10111 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010112}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010113
Eric Andersenc470f442003-07-28 09:56:35 +000010114/*
10115 * Set the input to take input from a file. If push is set, push the
10116 * old input onto the stack first.
10117 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010118static int
10119setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010120{
10121 int fd;
10122 int fd2;
10123
Denis Vlasenkob012b102007-02-19 22:43:01 +000010124 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010125 fd = open(fname, O_RDONLY);
10126 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010127 if (flags & INPUT_NOFILE_OK)
10128 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010129 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010130 }
Eric Andersenc470f442003-07-28 09:56:35 +000010131 if (fd < 10) {
10132 fd2 = copyfd(fd, 10);
10133 close(fd);
10134 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010135 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010136 fd = fd2;
10137 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010138 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010139 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010140 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010141 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010142}
10143
Eric Andersencb57d552001-06-28 07:25:16 +000010144/*
10145 * Like setinputfile, but takes input from a string.
10146 */
Eric Andersenc470f442003-07-28 09:56:35 +000010147static void
10148setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010149{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010150 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010151 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010152 g_parsefile->next_to_pgetc = string;
10153 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010154 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010155 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010156 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010157}
10158
10159
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010160/* ============ mail.c
10161 *
10162 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010163 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010164
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010165#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010166
Denys Vlasenko23841622015-10-09 15:52:03 +020010167/* Hash of mtimes of mailboxes */
10168static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010169/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010170static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010171
Eric Andersencb57d552001-06-28 07:25:16 +000010172/*
Eric Andersenc470f442003-07-28 09:56:35 +000010173 * Print appropriate message(s) if mail has arrived.
10174 * If mail_var_path_changed is set,
10175 * then the value of MAIL has mail_var_path_changed,
10176 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010177 */
Eric Andersenc470f442003-07-28 09:56:35 +000010178static void
10179chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010180{
Eric Andersencb57d552001-06-28 07:25:16 +000010181 const char *mpath;
10182 char *p;
10183 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010184 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010185 struct stackmark smark;
10186 struct stat statb;
10187
Eric Andersencb57d552001-06-28 07:25:16 +000010188 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010189 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010190 new_hash = 0;
10191 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010192 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010193 if (p == NULL)
10194 break;
10195 if (*p == '\0')
10196 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010197 for (q = p; *q; q++)
10198 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010199#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010200 if (q[-1] != '/')
10201 abort();
10202#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010203 q[-1] = '\0'; /* delete trailing '/' */
10204 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010205 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010206 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010207 /* Very simplistic "hash": just a sum of all mtimes */
10208 new_hash += (unsigned)statb.st_mtime;
10209 }
10210 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010211 if (mailtime_hash != 0)
10212 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010213 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010214 }
Eric Andersenc470f442003-07-28 09:56:35 +000010215 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010216 popstackmark(&smark);
10217}
Eric Andersencb57d552001-06-28 07:25:16 +000010218
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010219static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010220changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010221{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010222 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010223}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010224
Denis Vlasenko131ae172007-02-18 13:00:19 +000010225#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010226
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010227
10228/* ============ ??? */
10229
Eric Andersencb57d552001-06-28 07:25:16 +000010230/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010231 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010232 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010233static void
10234setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010235{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010236 char **newparam;
10237 char **ap;
10238 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010239
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010240 for (nparam = 0; argv[nparam]; nparam++)
10241 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010242 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10243 while (*argv) {
10244 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010245 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010246 *ap = NULL;
10247 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010248 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010249 shellparam.nparam = nparam;
10250 shellparam.p = newparam;
10251#if ENABLE_ASH_GETOPTS
10252 shellparam.optind = 1;
10253 shellparam.optoff = -1;
10254#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010255}
10256
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010257/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010258 * Process shell options. The global variable argptr contains a pointer
10259 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010260 *
10261 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10262 * For a non-interactive shell, an error condition encountered
10263 * by a special built-in ... shall cause the shell to write a diagnostic message
10264 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010265 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010266 * ...
10267 * Utility syntax error (option or operand error) Shall exit
10268 * ...
10269 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10270 * we see that bash does not do that (set "finishes" with error code 1 instead,
10271 * and shell continues), and people rely on this behavior!
10272 * Testcase:
10273 * set -o barfoo 2>/dev/null
10274 * echo $?
10275 *
10276 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010277 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010278static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010279plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010280{
10281 int i;
10282
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010283 if (name) {
10284 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010285 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010286 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010287 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010288 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010289 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010290 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010291 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010292 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010293 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010294 if (val) {
10295 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10296 } else {
10297 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10298 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010299 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010300 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010301}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010302static void
10303setoption(int flag, int val)
10304{
10305 int i;
10306
10307 for (i = 0; i < NOPTS; i++) {
10308 if (optletters(i) == flag) {
10309 optlist[i] = val;
10310 return;
10311 }
10312 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010313 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010314 /* NOTREACHED */
10315}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010316static int
Eric Andersenc470f442003-07-28 09:56:35 +000010317options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010318{
10319 char *p;
10320 int val;
10321 int c;
10322
10323 if (cmdline)
10324 minusc = NULL;
10325 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010326 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010327 if (c != '-' && c != '+')
10328 break;
10329 argptr++;
10330 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010331 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010332 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010333 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010334 if (!cmdline) {
10335 /* "-" means turn off -x and -v */
10336 if (p[0] == '\0')
10337 xflag = vflag = 0;
10338 /* "--" means reset params */
10339 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010340 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010341 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010342 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010343 }
Eric Andersencb57d552001-06-28 07:25:16 +000010344 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010345 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010346 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010347 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010348 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010349 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010350 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010351 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010352 /* it already printed err message */
10353 return 1; /* error */
10354 }
Eric Andersencb57d552001-06-28 07:25:16 +000010355 if (*argptr)
10356 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010357 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10358 isloginsh = 1;
10359 /* bash does not accept +-login, we also won't */
10360 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010361 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010362 isloginsh = 1;
10363 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010364 } else {
10365 setoption(c, val);
10366 }
10367 }
10368 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010369 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010370}
10371
Eric Andersencb57d552001-06-28 07:25:16 +000010372/*
Eric Andersencb57d552001-06-28 07:25:16 +000010373 * The shift builtin command.
10374 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010375static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010376shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010377{
10378 int n;
10379 char **ap1, **ap2;
10380
10381 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010382 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010383 n = number(argv[1]);
10384 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010385 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010386 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010387 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010388 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010389 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010390 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010391 }
10392 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010393 while ((*ap2++ = *ap1++) != NULL)
10394 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010395#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010396 shellparam.optind = 1;
10397 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010398#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010399 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010400 return 0;
10401}
10402
Eric Andersencb57d552001-06-28 07:25:16 +000010403/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010404 * POSIX requires that 'set' (but not export or readonly) output the
10405 * variables in lexicographic order - by the locale's collating order (sigh).
10406 * Maybe we could keep them in an ordered balanced binary tree
10407 * instead of hashed lists.
10408 * For now just roll 'em through qsort for printing...
10409 */
10410static int
10411showvars(const char *sep_prefix, int on, int off)
10412{
10413 const char *sep;
10414 char **ep, **epend;
10415
10416 ep = listvars(on, off, &epend);
10417 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10418
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010419 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010420
10421 for (; ep < epend; ep++) {
10422 const char *p;
10423 const char *q;
10424
10425 p = strchrnul(*ep, '=');
10426 q = nullstr;
10427 if (*p)
10428 q = single_quote(++p);
10429 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10430 }
10431 return 0;
10432}
10433
10434/*
Eric Andersencb57d552001-06-28 07:25:16 +000010435 * The set command builtin.
10436 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010437static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010438setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010439{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010440 int retval;
10441
Denis Vlasenko68404f12008-03-17 09:00:54 +000010442 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010443 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010444
Denis Vlasenkob012b102007-02-19 22:43:01 +000010445 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010446 retval = options(/*cmdline:*/ 0);
10447 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010448 optschanged();
10449 if (*argptr != NULL) {
10450 setparam(argptr);
10451 }
Eric Andersencb57d552001-06-28 07:25:16 +000010452 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010453 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010454 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010455}
10456
Denis Vlasenko131ae172007-02-18 13:00:19 +000010457#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010458static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010459change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010460{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010461 uint32_t t;
10462
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010463 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010464 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010465 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010466 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010467 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010468 vrandom.flags &= ~VNOFUNC;
10469 } else {
10470 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010471 t = strtoul(value, NULL, 10);
10472 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010473 }
Eric Andersenef02f822004-03-11 13:34:24 +000010474}
Eric Andersen16767e22004-03-16 05:14:10 +000010475#endif
10476
Denis Vlasenko131ae172007-02-18 13:00:19 +000010477#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010478static int
Eric Andersenc470f442003-07-28 09:56:35 +000010479getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010480{
10481 char *p, *q;
10482 char c = '?';
10483 int done = 0;
10484 int err = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010485 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010486 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010487
Denys Vlasenko9c541002015-10-07 15:44:36 +020010488 sbuf[1] = '\0';
10489
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010490 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010491 return 1;
10492 optnext = optfirst + *param_optind - 1;
10493
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010494 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010495 p = NULL;
10496 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010497 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010498 if (p == NULL || *p == '\0') {
10499 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010500 p = *optnext;
10501 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010502 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010503 p = NULL;
10504 done = 1;
10505 goto out;
10506 }
10507 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010508 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010509 goto atend;
10510 }
10511
10512 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010513 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010514 if (*q == '\0') {
10515 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010516 sbuf[0] = c;
10517 /*sbuf[1] = '\0'; - already is */
10518 err |= setvarsafe("OPTARG", sbuf, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010519 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010520 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010521 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010522 }
10523 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010524 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010525 }
10526 if (*++q == ':')
10527 q++;
10528 }
10529
10530 if (*++q == ':') {
10531 if (*p == '\0' && (p = *optnext) == NULL) {
10532 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010533 sbuf[0] = c;
10534 /*sbuf[1] = '\0'; - already is */
10535 err |= setvarsafe("OPTARG", sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010536 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010537 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010538 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010539 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010540 c = '?';
10541 }
Eric Andersenc470f442003-07-28 09:56:35 +000010542 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010543 }
10544
10545 if (p == *optnext)
10546 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010547 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010548 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010549 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010550 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010551 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010552 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010553 *param_optind = optnext - optfirst + 1;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010554 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC);
10555 sbuf[0] = c;
10556 /*sbuf[1] = '\0'; - already is */
10557 err |= setvarsafe(optvar, sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010558 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010559 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010560 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010561 flush_stdout_stderr();
10562 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010563 }
10564 return done;
10565}
Eric Andersenc470f442003-07-28 09:56:35 +000010566
10567/*
10568 * The getopts builtin. Shellparam.optnext points to the next argument
10569 * to be processed. Shellparam.optptr points to the next character to
10570 * be processed in the current argument. If shellparam.optnext is NULL,
10571 * then it's the first time getopts has been called.
10572 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010573static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010574getoptscmd(int argc, char **argv)
10575{
10576 char **optbase;
10577
10578 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010579 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010580 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010581 optbase = shellparam.p;
10582 if (shellparam.optind > shellparam.nparam + 1) {
10583 shellparam.optind = 1;
10584 shellparam.optoff = -1;
10585 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010586 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010587 optbase = &argv[3];
10588 if (shellparam.optind > argc - 2) {
10589 shellparam.optind = 1;
10590 shellparam.optoff = -1;
10591 }
10592 }
10593
10594 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010595 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010596}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010597#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010598
Eric Andersencb57d552001-06-28 07:25:16 +000010599
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010600/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010601
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010602struct heredoc {
10603 struct heredoc *next; /* next here document in list */
10604 union node *here; /* redirection node */
10605 char *eofmark; /* string indicating end of input */
10606 smallint striptabs; /* if set, strip leading tabs */
10607};
10608
10609static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010610static smallint quoteflag; /* set if (part of) last token was quoted */
10611static token_id_t lasttoken; /* last token read (integer id Txxx) */
10612static struct heredoc *heredoclist; /* list of here documents to read */
10613static char *wordtext; /* text of last word returned by readtoken */
10614static struct nodelist *backquotelist;
10615static union node *redirnode;
10616static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010617
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010618static const char *
10619tokname(char *buf, int tok)
10620{
10621 if (tok < TSEMI)
10622 return tokname_array[tok] + 1;
10623 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10624 return buf;
10625}
10626
10627/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010628 * Called when an unexpected token is read during the parse. The argument
10629 * is the token that is expected, or -1 if more than one type of token can
10630 * occur at this point.
10631 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010632static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010633static void
10634raise_error_unexpected_syntax(int token)
10635{
10636 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010637 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010638 int l;
10639
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010640 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010641 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010642 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010643 raise_error_syntax(msg);
10644 /* NOTREACHED */
10645}
Eric Andersencb57d552001-06-28 07:25:16 +000010646
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010647#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010648
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010649/* parsing is heavily cross-recursive, need these forward decls */
10650static union node *andor(void);
10651static union node *pipeline(void);
10652static union node *parse_command(void);
10653static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010654static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010655static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010656
Eric Andersenc470f442003-07-28 09:56:35 +000010657static union node *
10658list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010659{
10660 union node *n1, *n2, *n3;
10661 int tok;
10662
Eric Andersencb57d552001-06-28 07:25:16 +000010663 n1 = NULL;
10664 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010665 switch (peektoken()) {
10666 case TNL:
10667 if (!(nlflag & 1))
10668 break;
10669 parseheredoc();
10670 return n1;
10671
10672 case TEOF:
10673 if (!n1 && (nlflag & 1))
10674 n1 = NODE_EOF;
10675 parseheredoc();
10676 return n1;
10677 }
10678
10679 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10680 if (nlflag == 2 && tokname_array[peektoken()][0])
10681 return n1;
10682 nlflag |= 2;
10683
Eric Andersencb57d552001-06-28 07:25:16 +000010684 n2 = andor();
10685 tok = readtoken();
10686 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010687 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010688 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010689 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010690 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010691 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010692 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010693 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010694 n2 = n3;
10695 }
10696 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010697 }
10698 }
10699 if (n1 == NULL) {
10700 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010701 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010702 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010703 n3->type = NSEMI;
10704 n3->nbinary.ch1 = n1;
10705 n3->nbinary.ch2 = n2;
10706 n1 = n3;
10707 }
10708 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010709 case TNL:
10710 case TEOF:
10711 tokpushback = 1;
10712 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010713 case TBACKGND:
10714 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010715 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010716 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010717 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010718 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010719 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010720 return n1;
10721 }
10722 }
10723}
10724
Eric Andersenc470f442003-07-28 09:56:35 +000010725static union node *
10726andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010727{
Eric Andersencb57d552001-06-28 07:25:16 +000010728 union node *n1, *n2, *n3;
10729 int t;
10730
Eric Andersencb57d552001-06-28 07:25:16 +000010731 n1 = pipeline();
10732 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010733 t = readtoken();
10734 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010735 t = NAND;
10736 } else if (t == TOR) {
10737 t = NOR;
10738 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010739 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010740 return n1;
10741 }
Eric Andersenc470f442003-07-28 09:56:35 +000010742 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010743 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010744 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010745 n3->type = t;
10746 n3->nbinary.ch1 = n1;
10747 n3->nbinary.ch2 = n2;
10748 n1 = n3;
10749 }
10750}
10751
Eric Andersenc470f442003-07-28 09:56:35 +000010752static union node *
10753pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010754{
Eric Andersencb57d552001-06-28 07:25:16 +000010755 union node *n1, *n2, *pipenode;
10756 struct nodelist *lp, *prev;
10757 int negate;
10758
10759 negate = 0;
10760 TRACE(("pipeline: entered\n"));
10761 if (readtoken() == TNOT) {
10762 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010763 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010764 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010765 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010766 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010767 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010768 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010769 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010770 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010771 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010772 pipenode->npipe.cmdlist = lp;
10773 lp->n = n1;
10774 do {
10775 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010776 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010777 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010778 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010779 prev->next = lp;
10780 } while (readtoken() == TPIPE);
10781 lp->next = NULL;
10782 n1 = pipenode;
10783 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010784 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010785 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010786 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010787 n2->type = NNOT;
10788 n2->nnot.com = n1;
10789 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010790 }
10791 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010792}
10793
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010794static union node *
10795makename(void)
10796{
10797 union node *n;
10798
Denis Vlasenko597906c2008-02-20 16:38:54 +000010799 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010800 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010801 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010802 n->narg.text = wordtext;
10803 n->narg.backquote = backquotelist;
10804 return n;
10805}
10806
10807static void
10808fixredir(union node *n, const char *text, int err)
10809{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010810 int fd;
10811
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010812 TRACE(("Fix redir %s %d\n", text, err));
10813 if (!err)
10814 n->ndup.vname = NULL;
10815
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010816 fd = bb_strtou(text, NULL, 10);
10817 if (!errno && fd >= 0)
10818 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010819 else if (LONE_DASH(text))
10820 n->ndup.dupfd = -1;
10821 else {
10822 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010823 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010824 n->ndup.vname = makename();
10825 }
10826}
10827
10828/*
10829 * Returns true if the text contains nothing to expand (no dollar signs
10830 * or backquotes).
10831 */
10832static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010833noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010834{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010835 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010836
Denys Vlasenkocd716832009-11-28 22:14:02 +010010837 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010838 if (c == CTLQUOTEMARK)
10839 continue;
10840 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010841 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010842 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010843 return 0;
10844 }
10845 return 1;
10846}
10847
10848static void
10849parsefname(void)
10850{
10851 union node *n = redirnode;
10852
10853 if (readtoken() != TWORD)
10854 raise_error_unexpected_syntax(-1);
10855 if (n->type == NHERE) {
10856 struct heredoc *here = heredoc;
10857 struct heredoc *p;
10858 int i;
10859
10860 if (quoteflag == 0)
10861 n->type = NXHERE;
10862 TRACE(("Here document %d\n", n->type));
10863 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010864 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010865 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010866 here->eofmark = wordtext;
10867 here->next = NULL;
10868 if (heredoclist == NULL)
10869 heredoclist = here;
10870 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010871 for (p = heredoclist; p->next; p = p->next)
10872 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010873 p->next = here;
10874 }
10875 } else if (n->type == NTOFD || n->type == NFROMFD) {
10876 fixredir(n, wordtext, 0);
10877 } else {
10878 n->nfile.fname = makename();
10879 }
10880}
Eric Andersencb57d552001-06-28 07:25:16 +000010881
Eric Andersenc470f442003-07-28 09:56:35 +000010882static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010883simplecmd(void)
10884{
10885 union node *args, **app;
10886 union node *n = NULL;
10887 union node *vars, **vpp;
10888 union node **rpp, *redir;
10889 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010890#if ENABLE_ASH_BASH_COMPAT
10891 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000010892 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010893#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010894
10895 args = NULL;
10896 app = &args;
10897 vars = NULL;
10898 vpp = &vars;
10899 redir = NULL;
10900 rpp = &redir;
10901
10902 savecheckkwd = CHKALIAS;
10903 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010904 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010905 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010906 t = readtoken();
10907 switch (t) {
10908#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000010909 case TFUNCTION:
10910 if (peektoken() != TWORD)
10911 raise_error_unexpected_syntax(TWORD);
10912 function_flag = 1;
10913 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010914 case TAND: /* "&&" */
10915 case TOR: /* "||" */
10916 if (!double_brackets_flag) {
10917 tokpushback = 1;
10918 goto out;
10919 }
10920 wordtext = (char *) (t == TAND ? "-a" : "-o");
10921#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010922 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010923 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010924 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010925 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010926 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010927#if ENABLE_ASH_BASH_COMPAT
10928 if (strcmp("[[", wordtext) == 0)
10929 double_brackets_flag = 1;
10930 else if (strcmp("]]", wordtext) == 0)
10931 double_brackets_flag = 0;
10932#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010933 n->narg.backquote = backquotelist;
10934 if (savecheckkwd && isassignment(wordtext)) {
10935 *vpp = n;
10936 vpp = &n->narg.next;
10937 } else {
10938 *app = n;
10939 app = &n->narg.next;
10940 savecheckkwd = 0;
10941 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000010942#if ENABLE_ASH_BASH_COMPAT
10943 if (function_flag) {
10944 checkkwd = CHKNL | CHKKWD;
10945 switch (peektoken()) {
10946 case TBEGIN:
10947 case TIF:
10948 case TCASE:
10949 case TUNTIL:
10950 case TWHILE:
10951 case TFOR:
10952 goto do_func;
10953 case TLP:
10954 function_flag = 0;
10955 break;
10956 case TWORD:
10957 if (strcmp("[[", wordtext) == 0)
10958 goto do_func;
10959 /* fall through */
10960 default:
10961 raise_error_unexpected_syntax(-1);
10962 }
10963 }
10964#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010965 break;
10966 case TREDIR:
10967 *rpp = n = redirnode;
10968 rpp = &n->nfile.next;
10969 parsefname(); /* read name of redirection file */
10970 break;
10971 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000010972 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010973 if (args && app == &args->narg.next
10974 && !vars && !redir
10975 ) {
10976 struct builtincmd *bcmd;
10977 const char *name;
10978
10979 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000010980 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010981 raise_error_unexpected_syntax(TRP);
10982 name = n->narg.text;
10983 if (!goodname(name)
10984 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10985 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010986 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010987 }
10988 n->type = NDEFUN;
10989 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10990 n->narg.next = parse_command();
10991 return n;
10992 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000010993 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010994 /* fall through */
10995 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010996 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010997 goto out;
10998 }
10999 }
11000 out:
11001 *app = NULL;
11002 *vpp = NULL;
11003 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011004 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011005 n->type = NCMD;
11006 n->ncmd.args = args;
11007 n->ncmd.assign = vars;
11008 n->ncmd.redirect = redir;
11009 return n;
11010}
11011
11012static union node *
11013parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011014{
Eric Andersencb57d552001-06-28 07:25:16 +000011015 union node *n1, *n2;
11016 union node *ap, **app;
11017 union node *cp, **cpp;
11018 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011019 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011020 int t;
11021
11022 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011023 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011024
Eric Andersencb57d552001-06-28 07:25:16 +000011025 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011026 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011027 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011028 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011029 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011030 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011031 n1->type = NIF;
11032 n1->nif.test = list(0);
11033 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011034 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011035 n1->nif.ifpart = list(0);
11036 n2 = n1;
11037 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011038 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011039 n2 = n2->nif.elsepart;
11040 n2->type = NIF;
11041 n2->nif.test = list(0);
11042 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011043 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011044 n2->nif.ifpart = list(0);
11045 }
11046 if (lasttoken == TELSE)
11047 n2->nif.elsepart = list(0);
11048 else {
11049 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011050 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011051 }
Eric Andersenc470f442003-07-28 09:56:35 +000011052 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011053 break;
11054 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011055 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011056 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011057 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011058 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011059 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011060 got = readtoken();
11061 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011062 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000011063 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011064 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011065 }
11066 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011067 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011068 break;
11069 }
11070 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011071 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011072 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011073 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011074 n1->type = NFOR;
11075 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011076 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011077 if (readtoken() == TIN) {
11078 app = &ap;
11079 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011080 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011081 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011082 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011083 n2->narg.text = wordtext;
11084 n2->narg.backquote = backquotelist;
11085 *app = n2;
11086 app = &n2->narg.next;
11087 }
11088 *app = NULL;
11089 n1->nfor.args = ap;
11090 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011091 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011092 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011093 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011094 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011095 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011096 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011097 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011098 n1->nfor.args = n2;
11099 /*
11100 * Newline or semicolon here is optional (but note
11101 * that the original Bourne shell only allowed NL).
11102 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011103 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011104 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011105 }
Eric Andersenc470f442003-07-28 09:56:35 +000011106 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011107 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011108 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011109 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011110 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011111 break;
11112 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011113 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011114 n1->type = NCASE;
11115 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011116 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011117 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011118 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011119 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011120 n2->narg.text = wordtext;
11121 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011122 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11123 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011124 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011125 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011126 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011127 checkkwd = CHKNL | CHKKWD;
11128 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011129 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011130 if (lasttoken == TLP)
11131 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011132 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011133 cp->type = NCLIST;
11134 app = &cp->nclist.pattern;
11135 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011136 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011137 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011138 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011139 ap->narg.text = wordtext;
11140 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011141 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011142 break;
11143 app = &ap->narg.next;
11144 readtoken();
11145 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011146 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011147 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011148 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011149 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011150
Eric Andersenc470f442003-07-28 09:56:35 +000011151 cpp = &cp->nclist.next;
11152
11153 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011154 t = readtoken();
11155 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011156 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011157 raise_error_unexpected_syntax(TENDCASE);
11158 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011159 }
Eric Andersenc470f442003-07-28 09:56:35 +000011160 }
Eric Andersencb57d552001-06-28 07:25:16 +000011161 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011162 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011163 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011164 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011165 n1->type = NSUBSHELL;
11166 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011167 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011168 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011169 break;
11170 case TBEGIN:
11171 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011172 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011173 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011174 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011175 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011176 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011177 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011178 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011179 }
11180
Eric Andersenc470f442003-07-28 09:56:35 +000011181 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011182 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011183
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011184 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011185 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011186 checkkwd = CHKKWD | CHKALIAS;
11187 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011188 while (readtoken() == TREDIR) {
11189 *rpp = n2 = redirnode;
11190 rpp = &n2->nfile.next;
11191 parsefname();
11192 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011193 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011194 *rpp = NULL;
11195 if (redir) {
11196 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011197 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011198 n2->type = NREDIR;
11199 n2->nredir.n = n1;
11200 n1 = n2;
11201 }
11202 n1->nredir.redirect = redir;
11203 }
Eric Andersencb57d552001-06-28 07:25:16 +000011204 return n1;
11205}
11206
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011207#if ENABLE_ASH_BASH_COMPAT
11208static int decode_dollar_squote(void)
11209{
11210 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11211 int c, cnt;
11212 char *p;
11213 char buf[4];
11214
11215 c = pgetc();
11216 p = strchr(C_escapes, c);
11217 if (p) {
11218 buf[0] = c;
11219 p = buf;
11220 cnt = 3;
11221 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11222 do {
11223 c = pgetc();
11224 *++p = c;
11225 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11226 pungetc();
11227 } else if (c == 'x') { /* \xHH */
11228 do {
11229 c = pgetc();
11230 *++p = c;
11231 } while (isxdigit(c) && --cnt);
11232 pungetc();
11233 if (cnt == 3) { /* \x but next char is "bad" */
11234 c = 'x';
11235 goto unrecognized;
11236 }
11237 } else { /* simple seq like \\ or \t */
11238 p++;
11239 }
11240 *p = '\0';
11241 p = buf;
11242 c = bb_process_escape_sequence((void*)&p);
11243 } else { /* unrecognized "\z": print both chars unless ' or " */
11244 if (c != '\'' && c != '"') {
11245 unrecognized:
11246 c |= 0x100; /* "please encode \, then me" */
11247 }
11248 }
11249 return c;
11250}
11251#endif
11252
Eric Andersencb57d552001-06-28 07:25:16 +000011253/*
11254 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11255 * is not NULL, read a here document. In the latter case, eofmark is the
11256 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011257 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011258 * is the first character of the input token or document.
11259 *
11260 * Because C does not have internal subroutines, I have simulated them
11261 * using goto's to implement the subroutine linkage. The following macros
11262 * will run code that appears at the end of readtoken1.
11263 */
Eric Andersen2870d962001-07-02 17:27:21 +000011264#define CHECKEND() {goto checkend; checkend_return:;}
11265#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11266#define PARSESUB() {goto parsesub; parsesub_return:;}
11267#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11268#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11269#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011270static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011271readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011272{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011273 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011274 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011275 char *out;
Denys Vlasenko50e6d422016-09-30 11:35:54 +020011276 size_t len;
Eric Andersencb57d552001-06-28 07:25:16 +000011277 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011278 struct nodelist *bqlist;
11279 smallint quotef;
11280 smallint dblquote;
11281 smallint oldstyle;
11282 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011283#if ENABLE_ASH_EXPAND_PRMT
11284 smallint pssyntax; /* we are expanding a prompt string */
11285#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011286 int varnest; /* levels of variables expansion */
11287 int arinest; /* levels of arithmetic expansion */
11288 int parenlevel; /* levels of parens in arithmetic */
11289 int dqvarnest; /* levels of variables expansion within double quotes */
11290
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011291 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011292
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011293 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011294 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011295 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011296 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011297#if ENABLE_ASH_EXPAND_PRMT
11298 pssyntax = (syntax == PSSYNTAX);
11299 if (pssyntax)
11300 syntax = DQSYNTAX;
11301#endif
11302 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011303 varnest = 0;
11304 arinest = 0;
11305 parenlevel = 0;
11306 dqvarnest = 0;
11307
11308 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011309 loop:
11310 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011311 CHECKEND(); /* set c to PEOF if at end of here document */
11312 for (;;) { /* until end of line or end of word */
11313 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11314 switch (SIT(c, syntax)) {
11315 case CNL: /* '\n' */
11316 if (syntax == BASESYNTAX)
11317 goto endword; /* exit outer loop */
11318 USTPUTC(c, out);
11319 g_parsefile->linno++;
11320 setprompt_if(doprompt, 2);
11321 c = pgetc();
11322 goto loop; /* continue outer loop */
11323 case CWORD:
11324 USTPUTC(c, out);
11325 break;
11326 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011327#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011328 if (c == '\\' && bash_dollar_squote) {
11329 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011330 if (c == '\0') {
11331 /* skip $'\000', $'\x00' (like bash) */
11332 break;
11333 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011334 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011335 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011336 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011337 if (eofmark == NULL || dblquote)
11338 USTPUTC(CTLESC, out);
11339 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011340 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011341 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011342#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011343 if (eofmark == NULL || dblquote)
11344 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011345 USTPUTC(c, out);
11346 break;
11347 case CBACK: /* backslash */
11348 c = pgetc_without_PEOA();
11349 if (c == PEOF) {
11350 USTPUTC(CTLESC, out);
11351 USTPUTC('\\', out);
11352 pungetc();
11353 } else if (c == '\n') {
11354 setprompt_if(doprompt, 2);
11355 } else {
11356#if ENABLE_ASH_EXPAND_PRMT
11357 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011358 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011359 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011360 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011361#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011362 /* Backslash is retained if we are in "str" and next char isn't special */
11363 if (dblquote
11364 && c != '\\'
11365 && c != '`'
11366 && c != '$'
11367 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011368 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011369 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011370 }
Ron Yorston549deab2015-05-18 09:57:51 +020011371 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011372 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011373 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011374 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011375 break;
11376 case CSQUOTE:
11377 syntax = SQSYNTAX;
11378 quotemark:
11379 if (eofmark == NULL) {
11380 USTPUTC(CTLQUOTEMARK, out);
11381 }
11382 break;
11383 case CDQUOTE:
11384 syntax = DQSYNTAX;
11385 dblquote = 1;
11386 goto quotemark;
11387 case CENDQUOTE:
11388 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011389 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011390 USTPUTC(c, out);
11391 } else {
11392 if (dqvarnest == 0) {
11393 syntax = BASESYNTAX;
11394 dblquote = 0;
11395 }
11396 quotef = 1;
11397 goto quotemark;
11398 }
11399 break;
11400 case CVAR: /* '$' */
11401 PARSESUB(); /* parse substitution */
11402 break;
11403 case CENDVAR: /* '}' */
11404 if (varnest > 0) {
11405 varnest--;
11406 if (dqvarnest > 0) {
11407 dqvarnest--;
11408 }
11409 c = CTLENDVAR;
11410 }
11411 USTPUTC(c, out);
11412 break;
11413#if ENABLE_SH_MATH_SUPPORT
11414 case CLP: /* '(' in arithmetic */
11415 parenlevel++;
11416 USTPUTC(c, out);
11417 break;
11418 case CRP: /* ')' in arithmetic */
11419 if (parenlevel > 0) {
11420 parenlevel--;
11421 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011422 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011423 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011424 if (--arinest == 0) {
11425 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011426 }
11427 } else {
11428 /*
11429 * unbalanced parens
11430 * (don't 2nd guess - no error)
11431 */
11432 pungetc();
11433 }
11434 }
11435 USTPUTC(c, out);
11436 break;
11437#endif
11438 case CBQUOTE: /* '`' */
11439 PARSEBACKQOLD();
11440 break;
11441 case CENDFILE:
11442 goto endword; /* exit outer loop */
11443 case CIGN:
11444 break;
11445 default:
11446 if (varnest == 0) {
11447#if ENABLE_ASH_BASH_COMPAT
11448 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011449//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011450 if (pgetc() == '>')
11451 c = 0x100 + '>'; /* flag &> */
11452 pungetc();
11453 }
11454#endif
11455 goto endword; /* exit outer loop */
11456 }
11457 IF_ASH_ALIAS(if (c != PEOA))
11458 USTPUTC(c, out);
11459 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011460 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011461 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011462 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011463
Mike Frysinger98c52642009-04-02 10:02:37 +000011464#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011465 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011466 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011467#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011468 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011469 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011470 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011471 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011472 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011473 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011474 }
11475 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011476 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011477 out = stackblock();
11478 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011479 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011480 && quotef == 0
11481 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011482 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011483 PARSEREDIR(); /* passed as params: out, c */
11484 lasttoken = TREDIR;
11485 return lasttoken;
11486 }
11487 /* else: non-number X seen, interpret it
11488 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011489 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011490 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011491 }
11492 quoteflag = quotef;
11493 backquotelist = bqlist;
11494 grabstackblock(len);
11495 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011496 lasttoken = TWORD;
11497 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011498/* end of readtoken routine */
11499
Eric Andersencb57d552001-06-28 07:25:16 +000011500/*
11501 * Check to see whether we are at the end of the here document. When this
11502 * is called, c is set to the first character of the next input line. If
11503 * we are at the end of the here document, this routine sets the c to PEOF.
11504 */
Eric Andersenc470f442003-07-28 09:56:35 +000011505checkend: {
11506 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011507#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011508 if (c == PEOA)
11509 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011510#endif
11511 if (striptabs) {
11512 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011513 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011514 }
Eric Andersenc470f442003-07-28 09:56:35 +000011515 }
11516 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011517 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011518 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011519
Eric Andersenc470f442003-07-28 09:56:35 +000011520 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011521 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11522 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011523 if (*p == '\n' && *q == '\0') {
11524 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011525 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011526 needprompt = doprompt;
11527 } else {
11528 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011529 }
11530 }
11531 }
11532 }
Eric Andersenc470f442003-07-28 09:56:35 +000011533 goto checkend_return;
11534}
Eric Andersencb57d552001-06-28 07:25:16 +000011535
Eric Andersencb57d552001-06-28 07:25:16 +000011536/*
11537 * Parse a redirection operator. The variable "out" points to a string
11538 * specifying the fd to be redirected. The variable "c" contains the
11539 * first character of the redirection operator.
11540 */
Eric Andersenc470f442003-07-28 09:56:35 +000011541parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011542 /* out is already checked to be a valid number or "" */
11543 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011544 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011545
Denis Vlasenko597906c2008-02-20 16:38:54 +000011546 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011547 if (c == '>') {
11548 np->nfile.fd = 1;
11549 c = pgetc();
11550 if (c == '>')
11551 np->type = NAPPEND;
11552 else if (c == '|')
11553 np->type = NCLOBBER;
11554 else if (c == '&')
11555 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011556 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011557 else {
11558 np->type = NTO;
11559 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011560 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011561 }
11562#if ENABLE_ASH_BASH_COMPAT
11563 else if (c == 0x100 + '>') { /* this flags &> redirection */
11564 np->nfile.fd = 1;
11565 pgetc(); /* this is '>', no need to check */
11566 np->type = NTO2;
11567 }
11568#endif
11569 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011570 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011571 c = pgetc();
11572 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011573 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011574 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011575 np = stzalloc(sizeof(struct nhere));
11576 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011577 }
11578 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011579 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011580 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011581 c = pgetc();
11582 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011583 heredoc->striptabs = 1;
11584 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011585 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011586 pungetc();
11587 }
11588 break;
11589
11590 case '&':
11591 np->type = NFROMFD;
11592 break;
11593
11594 case '>':
11595 np->type = NFROMTO;
11596 break;
11597
11598 default:
11599 np->type = NFROM;
11600 pungetc();
11601 break;
11602 }
Eric Andersencb57d552001-06-28 07:25:16 +000011603 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011604 if (fd >= 0)
11605 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011606 redirnode = np;
11607 goto parseredir_return;
11608}
Eric Andersencb57d552001-06-28 07:25:16 +000011609
Eric Andersencb57d552001-06-28 07:25:16 +000011610/*
11611 * Parse a substitution. At this point, we have read the dollar sign
11612 * and nothing else.
11613 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011614
11615/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11616 * (assuming ascii char codes, as the original implementation did) */
11617#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011618 (((unsigned)(c) - 33 < 32) \
11619 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011620parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011621 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011622 int typeloc;
11623 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011624
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011625 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011626 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011627 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011628 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011629#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011630 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011631 bash_dollar_squote = 1;
11632 else
11633#endif
11634 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011635 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011636 } else if (c == '(') {
11637 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011638 if (pgetc_eatbnl() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011639#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011640 PARSEARITH();
11641#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011642 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011643#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011644 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011645 pungetc();
11646 PARSEBACKQNEW();
11647 }
11648 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011649 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011650 USTPUTC(CTLVAR, out);
11651 typeloc = out - (char *)stackblock();
11652 USTPUTC(VSNORMAL, out);
11653 subtype = VSNORMAL;
11654 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011655 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000011656 if (c == '#') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011657 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011658 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011659 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011660 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011661 subtype = VSLENGTH; /* ${#VAR} */
11662 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011663 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011664 }
Eric Andersenc470f442003-07-28 09:56:35 +000011665 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011666 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011667 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011668 do {
11669 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011670 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011671 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011672 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011673 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011674 do {
11675 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011676 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011677 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011678 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011679 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011680 USTPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011681 c = pgetc_eatbnl();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011682 } else {
11683 badsub:
11684 raise_error_syntax("bad substitution");
11685 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011686 if (c != '}' && subtype == VSLENGTH) {
11687 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011688 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011689 }
Eric Andersencb57d552001-06-28 07:25:16 +000011690
Eric Andersenc470f442003-07-28 09:56:35 +000011691 STPUTC('=', out);
11692 flags = 0;
11693 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011694 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011695 /* ${VAR...} but not $VAR or ${#VAR} */
11696 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011697 switch (c) {
11698 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011699 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011700#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011701 /* This check is only needed to not misinterpret
11702 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11703 * constructs.
11704 */
11705 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011706 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011707 pungetc();
11708 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011709 }
11710#endif
11711 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011712 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011713 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011714 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011715 if (p == NULL)
11716 goto badsub;
11717 subtype = p - types + VSNORMAL;
11718 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011719 }
Eric Andersenc470f442003-07-28 09:56:35 +000011720 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011721 case '#': {
11722 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011723 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011724 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011725 if (c != cc)
11726 goto do_pungetc;
11727 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011728 break;
11729 }
11730#if ENABLE_ASH_BASH_COMPAT
11731 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011732 /* ${v/[/]pattern/repl} */
11733//TODO: encode pattern and repl separately.
11734// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011735 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011736 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011737 if (c != '/')
11738 goto do_pungetc;
11739 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011740 break;
11741#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011742 }
Eric Andersenc470f442003-07-28 09:56:35 +000011743 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011744 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011745 pungetc();
11746 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011747 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011748 if (subtype != VSNORMAL) {
11749 varnest++;
Ron Yorston7e4ed262015-05-18 09:54:43 +020011750 if (dblquote) {
Eric Andersenc470f442003-07-28 09:56:35 +000011751 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011752 }
11753 }
11754 }
Eric Andersenc470f442003-07-28 09:56:35 +000011755 goto parsesub_return;
11756}
Eric Andersencb57d552001-06-28 07:25:16 +000011757
Eric Andersencb57d552001-06-28 07:25:16 +000011758/*
11759 * Called to parse command substitutions. Newstyle is set if the command
11760 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11761 * list of commands (passed by reference), and savelen is the number of
11762 * characters on the top of the stack which must be preserved.
11763 */
Eric Andersenc470f442003-07-28 09:56:35 +000011764parsebackq: {
11765 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011766 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011767 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011768 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011769 smallint saveprompt = 0;
11770
Eric Andersenc470f442003-07-28 09:56:35 +000011771 str = NULL;
11772 savelen = out - (char *)stackblock();
11773 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011774 /*
11775 * FIXME: this can allocate very large block on stack and SEGV.
11776 * Example:
11777 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011778 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011779 * a hundred command substitutions stack overflows.
11780 * With larger prepended string, SEGV happens sooner.
11781 */
Ron Yorston072fc602015-07-01 16:46:18 +010011782 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011783 memcpy(str, stackblock(), savelen);
11784 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011785
Eric Andersenc470f442003-07-28 09:56:35 +000011786 if (oldstyle) {
11787 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011788 * treatment to some slashes, and then push the string and
11789 * reread it as input, interpreting it normally.
11790 */
Eric Andersenc470f442003-07-28 09:56:35 +000011791 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011792 size_t psavelen;
11793 char *pstr;
11794
Eric Andersenc470f442003-07-28 09:56:35 +000011795 STARTSTACKSTR(pout);
11796 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011797 int pc;
11798
11799 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011800 pc = pgetc();
11801 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011802 case '`':
11803 goto done;
11804
11805 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011806 pc = pgetc();
11807 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011808 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011809 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011810 /*
11811 * If eating a newline, avoid putting
11812 * the newline into the new character
11813 * stream (via the STPUTC after the
11814 * switch).
11815 */
11816 continue;
11817 }
11818 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011819 && (!dblquote || pc != '"')
11820 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011821 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011822 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011823 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011824 break;
11825 }
11826 /* fall through */
11827
11828 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011829 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011830 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011831 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011832
11833 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011834 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011835 needprompt = doprompt;
11836 break;
11837
11838 default:
11839 break;
11840 }
11841 STPUTC(pc, pout);
11842 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011843 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011844 STPUTC('\0', pout);
11845 psavelen = pout - (char *)stackblock();
11846 if (psavelen > 0) {
11847 pstr = grabstackstr(pout);
11848 setinputstring(pstr);
11849 }
11850 }
11851 nlpp = &bqlist;
11852 while (*nlpp)
11853 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011854 *nlpp = stzalloc(sizeof(**nlpp));
11855 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011856
11857 if (oldstyle) {
11858 saveprompt = doprompt;
11859 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011860 }
11861
Eric Andersenc470f442003-07-28 09:56:35 +000011862 n = list(2);
11863
11864 if (oldstyle)
11865 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011866 else if (readtoken() != TRP)
11867 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011868
11869 (*nlpp)->n = n;
11870 if (oldstyle) {
11871 /*
11872 * Start reading from old file again, ignoring any pushed back
11873 * tokens left from the backquote parsing
11874 */
11875 popfile();
11876 tokpushback = 0;
11877 }
11878 while (stackblocksize() <= savelen)
11879 growstackblock();
11880 STARTSTACKSTR(out);
11881 if (str) {
11882 memcpy(out, str, savelen);
11883 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011884 }
Ron Yorston549deab2015-05-18 09:57:51 +020011885 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011886 if (oldstyle)
11887 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011888 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011889}
11890
Mike Frysinger98c52642009-04-02 10:02:37 +000011891#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011892/*
11893 * Parse an arithmetic expansion (indicate start of one and set state)
11894 */
Eric Andersenc470f442003-07-28 09:56:35 +000011895parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011896 if (++arinest == 1) {
11897 prevsyntax = syntax;
11898 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011899 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011900 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011901 goto parsearith_return;
11902}
11903#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011904} /* end of readtoken */
11905
Eric Andersencb57d552001-06-28 07:25:16 +000011906/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011907 * Read the next input token.
11908 * If the token is a word, we set backquotelist to the list of cmds in
11909 * backquotes. We set quoteflag to true if any part of the word was
11910 * quoted.
11911 * If the token is TREDIR, then we set redirnode to a structure containing
11912 * the redirection.
11913 * In all cases, the variable startlinno is set to the number of the line
11914 * on which the token starts.
11915 *
11916 * [Change comment: here documents and internal procedures]
11917 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11918 * word parsing code into a separate routine. In this case, readtoken
11919 * doesn't need to have any internal procedures, but parseword does.
11920 * We could also make parseoperator in essence the main routine, and
11921 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011922 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011923#define NEW_xxreadtoken
11924#ifdef NEW_xxreadtoken
11925/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011926static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011927 '\n', '(', ')', /* singles */
11928 '&', '|', ';', /* doubles */
11929 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011930};
Eric Andersencb57d552001-06-28 07:25:16 +000011931
Denis Vlasenko834dee72008-10-07 09:18:30 +000011932#define xxreadtoken_singles 3
11933#define xxreadtoken_doubles 3
11934
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011935static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011936 TNL, TLP, TRP, /* only single occurrence allowed */
11937 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11938 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011939 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011940};
11941
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011942static int
11943xxreadtoken(void)
11944{
11945 int c;
11946
11947 if (tokpushback) {
11948 tokpushback = 0;
11949 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011950 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011951 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011952 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011953 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011954 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011955 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011956 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011957
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011958 if (c == '#') {
11959 while ((c = pgetc()) != '\n' && c != PEOF)
11960 continue;
11961 pungetc();
11962 } else if (c == '\\') {
11963 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011964 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011965 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011966 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011967 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011968 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011969 } else {
11970 const char *p;
11971
11972 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11973 if (c != PEOF) {
11974 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011975 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011976 needprompt = doprompt;
11977 }
11978
11979 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011980 if (p == NULL)
11981 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011982
Denis Vlasenko834dee72008-10-07 09:18:30 +000011983 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11984 int cc = pgetc();
11985 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011986 p += xxreadtoken_doubles + 1;
11987 } else {
11988 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011989#if ENABLE_ASH_BASH_COMPAT
11990 if (c == '&' && cc == '>') /* &> */
11991 break; /* return readtoken1(...) */
11992#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011993 }
11994 }
11995 }
11996 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11997 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011998 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011999 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012000
12001 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012002}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012003#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012004#define RETURN(token) return lasttoken = token
12005static int
12006xxreadtoken(void)
12007{
12008 int c;
12009
12010 if (tokpushback) {
12011 tokpushback = 0;
12012 return lasttoken;
12013 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012014 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012015 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012016 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012017 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012018 switch (c) {
12019 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012020 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012021 continue;
12022 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012023 while ((c = pgetc()) != '\n' && c != PEOF)
12024 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012025 pungetc();
12026 continue;
12027 case '\\':
12028 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012029 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012030 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012031 continue;
12032 }
12033 pungetc();
12034 goto breakloop;
12035 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012036 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012037 needprompt = doprompt;
12038 RETURN(TNL);
12039 case PEOF:
12040 RETURN(TEOF);
12041 case '&':
12042 if (pgetc() == '&')
12043 RETURN(TAND);
12044 pungetc();
12045 RETURN(TBACKGND);
12046 case '|':
12047 if (pgetc() == '|')
12048 RETURN(TOR);
12049 pungetc();
12050 RETURN(TPIPE);
12051 case ';':
12052 if (pgetc() == ';')
12053 RETURN(TENDCASE);
12054 pungetc();
12055 RETURN(TSEMI);
12056 case '(':
12057 RETURN(TLP);
12058 case ')':
12059 RETURN(TRP);
12060 default:
12061 goto breakloop;
12062 }
12063 }
12064 breakloop:
12065 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12066#undef RETURN
12067}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012068#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012069
12070static int
12071readtoken(void)
12072{
12073 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012074 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012075#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012076 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012077#endif
12078
12079#if ENABLE_ASH_ALIAS
12080 top:
12081#endif
12082
12083 t = xxreadtoken();
12084
12085 /*
12086 * eat newlines
12087 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012088 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012089 while (t == TNL) {
12090 parseheredoc();
12091 t = xxreadtoken();
12092 }
12093 }
12094
12095 if (t != TWORD || quoteflag) {
12096 goto out;
12097 }
12098
12099 /*
12100 * check for keywords
12101 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012102 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012103 const char *const *pp;
12104
12105 pp = findkwd(wordtext);
12106 if (pp) {
12107 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012108 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012109 goto out;
12110 }
12111 }
12112
12113 if (checkkwd & CHKALIAS) {
12114#if ENABLE_ASH_ALIAS
12115 struct alias *ap;
12116 ap = lookupalias(wordtext, 1);
12117 if (ap != NULL) {
12118 if (*ap->val) {
12119 pushstring(ap->val, ap);
12120 }
12121 goto top;
12122 }
12123#endif
12124 }
12125 out:
12126 checkkwd = 0;
12127#if DEBUG
12128 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012129 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012130 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012131 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012132#endif
12133 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012134}
12135
Ron Yorstonc0e00762015-10-29 11:30:55 +000012136static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012137peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012138{
12139 int t;
12140
12141 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012142 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012143 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012144}
Eric Andersencb57d552001-06-28 07:25:16 +000012145
12146/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012147 * Read and parse a command. Returns NODE_EOF on end of file.
12148 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012149 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012150static union node *
12151parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012152{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012153 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012154 checkkwd = 0;
12155 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012156 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012157 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012158 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012159 return list(1);
12160}
12161
12162/*
12163 * Input any here documents.
12164 */
12165static void
12166parseheredoc(void)
12167{
12168 struct heredoc *here;
12169 union node *n;
12170
12171 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012172 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012173
12174 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012175 setprompt_if(needprompt, 2);
12176 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012177 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012178 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012179 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012180 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012181 n->narg.text = wordtext;
12182 n->narg.backquote = backquotelist;
12183 here->here->nhere.doc = n;
12184 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012185 }
Eric Andersencb57d552001-06-28 07:25:16 +000012186}
12187
12188
12189/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012190 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012191 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012192#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012193static const char *
12194expandstr(const char *ps)
12195{
12196 union node n;
12197
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012198 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12199 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012200 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012201 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012202 popfile();
12203
12204 n.narg.type = NARG;
12205 n.narg.next = NULL;
12206 n.narg.text = wordtext;
12207 n.narg.backquote = backquotelist;
12208
Ron Yorston549deab2015-05-18 09:57:51 +020012209 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012210 return stackblock();
12211}
12212#endif
12213
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012214/*
12215 * Execute a command or commands contained in a string.
12216 */
12217static int
12218evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012219{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012220 union node *n;
12221 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012222 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012223
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012224 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012225 setinputstring(s);
12226 setstackmark(&smark);
12227
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012228 status = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012229 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012230 int i;
12231
12232 i = evaltree(n, 0);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012233 if (n)
12234 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012235 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012236 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012237 break;
12238 }
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012239 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012240 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012241 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012242
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012243 evalskip &= mask;
12244 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012245}
12246
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012247/*
12248 * The eval command.
12249 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012250static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012251evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012252{
12253 char *p;
12254 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012255
Denis Vlasenko68404f12008-03-17 09:00:54 +000012256 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012257 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012258 argv += 2;
12259 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012260 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012261 for (;;) {
12262 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012263 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012264 if (p == NULL)
12265 break;
12266 STPUTC(' ', concat);
12267 }
12268 STPUTC('\0', concat);
12269 p = grabstackstr(concat);
12270 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012271 return evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012272 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012273 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012274}
12275
12276/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012277 * Read and execute commands.
12278 * "Top" is nonzero for the top level command loop;
12279 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012280 */
12281static int
12282cmdloop(int top)
12283{
12284 union node *n;
12285 struct stackmark smark;
12286 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012287 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012288 int numeof = 0;
12289
12290 TRACE(("cmdloop(%d) called\n", top));
12291 for (;;) {
12292 int skip;
12293
12294 setstackmark(&smark);
12295#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012296 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012297 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012298#endif
12299 inter = 0;
12300 if (iflag && top) {
12301 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012302 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012303 }
12304 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012305#if DEBUG
12306 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012307 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012308#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012309 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012310 if (!top || numeof >= 50)
12311 break;
12312 if (!stoppedjobs()) {
12313 if (!Iflag)
12314 break;
12315 out2str("\nUse \"exit\" to leave shell.\n");
12316 }
12317 numeof++;
12318 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012319 int i;
12320
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012321 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12322 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012323 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012324 i = evaltree(n, 0);
12325 if (n)
12326 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012327 }
12328 popstackmark(&smark);
12329 skip = evalskip;
12330
12331 if (skip) {
Denys Vlasenko6a0710e2016-09-30 14:18:34 +020012332 evalskip &= ~SKIPFUNC;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012333 return skip & SKIPEVAL;
12334 }
12335 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012336 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012337}
12338
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012339/*
12340 * Take commands from a file. To be compatible we should do a path
12341 * search for the file, which is necessary to find sub-commands.
12342 */
12343static char *
12344find_dot_file(char *name)
12345{
12346 char *fullname;
12347 const char *path = pathval();
12348 struct stat statb;
12349
12350 /* don't try this for absolute or relative paths */
12351 if (strchr(name, '/'))
12352 return name;
12353
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012354 /* IIRC standards do not say whether . is to be searched.
12355 * And it is even smaller this way, making it unconditional for now:
12356 */
12357 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12358 fullname = name;
12359 goto try_cur_dir;
12360 }
12361
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012362 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012363 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012364 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12365 /*
12366 * Don't bother freeing here, since it will
12367 * be freed by the caller.
12368 */
12369 return fullname;
12370 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012371 if (fullname != name)
12372 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012373 }
12374
12375 /* not found in the PATH */
12376 ash_msg_and_raise_error("%s: not found", name);
12377 /* NOTREACHED */
12378}
12379
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012380static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012381dotcmd(int argc, char **argv)
12382{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012383 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012384 struct strlist *sp;
12385 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012386
12387 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012388 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012389
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012390 if (!argv[1]) {
12391 /* bash says: "bash: .: filename argument required" */
12392 return 2; /* bash compat */
12393 }
12394
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012395 /* "false; . empty_file; echo $?" should print 0, not 1: */
12396 exitstatus = 0;
12397
Denys Vlasenko091f8312013-03-17 14:25:22 +010012398 /* This aborts if file isn't found, which is POSIXly correct.
12399 * bash returns exitcode 1 instead.
12400 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012401 fullname = find_dot_file(argv[1]);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012402 argv += 2;
12403 argc -= 2;
12404 if (argc) { /* argc > 0, argv[0] != NULL */
12405 saveparam = shellparam;
12406 shellparam.malloced = 0;
12407 shellparam.nparam = argc;
12408 shellparam.p = argv;
12409 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012410
Denys Vlasenko091f8312013-03-17 14:25:22 +010012411 /* This aborts if file can't be opened, which is POSIXly correct.
12412 * bash returns exitcode 1 instead.
12413 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012414 setinputfile(fullname, INPUT_PUSH_FILE);
12415 commandname = fullname;
12416 cmdloop(0);
12417 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012418
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012419 if (argc) {
12420 freeparam(&shellparam);
12421 shellparam = saveparam;
12422 };
12423
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012424 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012425}
12426
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012427static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012428exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012429{
12430 if (stoppedjobs())
12431 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012432 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012433 exitstatus = number(argv[1]);
12434 raise_exception(EXEXIT);
12435 /* NOTREACHED */
12436}
12437
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012438/*
12439 * Read a file containing shell functions.
12440 */
12441static void
12442readcmdfile(char *name)
12443{
12444 setinputfile(name, INPUT_PUSH_FILE);
12445 cmdloop(0);
12446 popfile();
12447}
12448
12449
Denis Vlasenkocc571512007-02-23 21:10:35 +000012450/* ============ find_command inplementation */
12451
12452/*
12453 * Resolve a command name. If you change this routine, you may have to
12454 * change the shellexec routine as well.
12455 */
12456static void
12457find_command(char *name, struct cmdentry *entry, int act, const char *path)
12458{
12459 struct tblentry *cmdp;
12460 int idx;
12461 int prev;
12462 char *fullname;
12463 struct stat statb;
12464 int e;
12465 int updatetbl;
12466 struct builtincmd *bcmd;
12467
12468 /* If name contains a slash, don't use PATH or hash table */
12469 if (strchr(name, '/') != NULL) {
12470 entry->u.index = -1;
12471 if (act & DO_ABS) {
12472 while (stat(name, &statb) < 0) {
12473#ifdef SYSV
12474 if (errno == EINTR)
12475 continue;
12476#endif
12477 entry->cmdtype = CMDUNKNOWN;
12478 return;
12479 }
12480 }
12481 entry->cmdtype = CMDNORMAL;
12482 return;
12483 }
12484
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012485/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012486
12487 updatetbl = (path == pathval());
12488 if (!updatetbl) {
12489 act |= DO_ALTPATH;
12490 if (strstr(path, "%builtin") != NULL)
12491 act |= DO_ALTBLTIN;
12492 }
12493
12494 /* If name is in the table, check answer will be ok */
12495 cmdp = cmdlookup(name, 0);
12496 if (cmdp != NULL) {
12497 int bit;
12498
12499 switch (cmdp->cmdtype) {
12500 default:
12501#if DEBUG
12502 abort();
12503#endif
12504 case CMDNORMAL:
12505 bit = DO_ALTPATH;
12506 break;
12507 case CMDFUNCTION:
12508 bit = DO_NOFUNC;
12509 break;
12510 case CMDBUILTIN:
12511 bit = DO_ALTBLTIN;
12512 break;
12513 }
12514 if (act & bit) {
12515 updatetbl = 0;
12516 cmdp = NULL;
12517 } else if (cmdp->rehash == 0)
12518 /* if not invalidated by cd, we're done */
12519 goto success;
12520 }
12521
12522 /* If %builtin not in path, check for builtin next */
12523 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012524 if (bcmd) {
12525 if (IS_BUILTIN_REGULAR(bcmd))
12526 goto builtin_success;
12527 if (act & DO_ALTPATH) {
12528 if (!(act & DO_ALTBLTIN))
12529 goto builtin_success;
12530 } else if (builtinloc <= 0) {
12531 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012532 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012533 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012534
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012535#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012536 {
12537 int applet_no = find_applet_by_name(name);
12538 if (applet_no >= 0) {
12539 entry->cmdtype = CMDNORMAL;
12540 entry->u.index = -2 - applet_no;
12541 return;
12542 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012543 }
12544#endif
12545
Denis Vlasenkocc571512007-02-23 21:10:35 +000012546 /* We have to search path. */
12547 prev = -1; /* where to start */
12548 if (cmdp && cmdp->rehash) { /* doing a rehash */
12549 if (cmdp->cmdtype == CMDBUILTIN)
12550 prev = builtinloc;
12551 else
12552 prev = cmdp->param.index;
12553 }
12554
12555 e = ENOENT;
12556 idx = -1;
12557 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012558 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012559 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012560 /* NB: code below will still use fullname
12561 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012562 idx++;
12563 if (pathopt) {
12564 if (prefix(pathopt, "builtin")) {
12565 if (bcmd)
12566 goto builtin_success;
12567 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012568 }
12569 if ((act & DO_NOFUNC)
12570 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012571 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012572 continue;
12573 }
12574 }
12575 /* if rehash, don't redo absolute path names */
12576 if (fullname[0] == '/' && idx <= prev) {
12577 if (idx < prev)
12578 continue;
12579 TRACE(("searchexec \"%s\": no change\n", name));
12580 goto success;
12581 }
12582 while (stat(fullname, &statb) < 0) {
12583#ifdef SYSV
12584 if (errno == EINTR)
12585 continue;
12586#endif
12587 if (errno != ENOENT && errno != ENOTDIR)
12588 e = errno;
12589 goto loop;
12590 }
12591 e = EACCES; /* if we fail, this will be the error */
12592 if (!S_ISREG(statb.st_mode))
12593 continue;
12594 if (pathopt) { /* this is a %func directory */
12595 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012596 /* NB: stalloc will return space pointed by fullname
12597 * (because we don't have any intervening allocations
12598 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012599 readcmdfile(fullname);
12600 cmdp = cmdlookup(name, 0);
12601 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12602 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12603 stunalloc(fullname);
12604 goto success;
12605 }
12606 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12607 if (!updatetbl) {
12608 entry->cmdtype = CMDNORMAL;
12609 entry->u.index = idx;
12610 return;
12611 }
12612 INT_OFF;
12613 cmdp = cmdlookup(name, 1);
12614 cmdp->cmdtype = CMDNORMAL;
12615 cmdp->param.index = idx;
12616 INT_ON;
12617 goto success;
12618 }
12619
12620 /* We failed. If there was an entry for this command, delete it */
12621 if (cmdp && updatetbl)
12622 delete_cmd_entry();
12623 if (act & DO_ERR)
12624 ash_msg("%s: %s", name, errmsg(e, "not found"));
12625 entry->cmdtype = CMDUNKNOWN;
12626 return;
12627
12628 builtin_success:
12629 if (!updatetbl) {
12630 entry->cmdtype = CMDBUILTIN;
12631 entry->u.cmd = bcmd;
12632 return;
12633 }
12634 INT_OFF;
12635 cmdp = cmdlookup(name, 1);
12636 cmdp->cmdtype = CMDBUILTIN;
12637 cmdp->param.cmd = bcmd;
12638 INT_ON;
12639 success:
12640 cmdp->rehash = 0;
12641 entry->cmdtype = cmdp->cmdtype;
12642 entry->u = cmdp->param;
12643}
12644
12645
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012646/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012647
Eric Andersencb57d552001-06-28 07:25:16 +000012648/*
Eric Andersencb57d552001-06-28 07:25:16 +000012649 * The trap builtin.
12650 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012651static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012652trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012653{
12654 char *action;
12655 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012656 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012657
Eric Andersenc470f442003-07-28 09:56:35 +000012658 nextopt(nullstr);
12659 ap = argptr;
12660 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012661 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012662 char *tr = trap_ptr[signo];
12663 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012664 /* note: bash adds "SIG", but only if invoked
12665 * as "bash". If called as "sh", or if set -o posix,
12666 * then it prints short signal names.
12667 * We are printing short names: */
12668 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012669 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012670 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012671 /* trap_ptr != trap only if we are in special-cased `trap` code.
12672 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012673 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012674 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012675 }
12676 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012677 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012678 if (trap_ptr != trap) {
12679 free(trap_ptr);
12680 trap_ptr = trap;
12681 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012682 */
Eric Andersencb57d552001-06-28 07:25:16 +000012683 return 0;
12684 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012685
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012686 action = NULL;
12687 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012688 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012689 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012690 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012691 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012692 if (signo < 0) {
12693 /* Mimic bash message exactly */
12694 ash_msg("%s: invalid signal specification", *ap);
12695 exitcode = 1;
12696 goto next;
12697 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012698 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012699 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012700 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012701 action = NULL;
12702 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012703 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012704 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012705 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012706 if (action)
12707 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012708 trap[signo] = action;
12709 if (signo != 0)
12710 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012711 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012712 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012713 ap++;
12714 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012715 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012716}
12717
Eric Andersenc470f442003-07-28 09:56:35 +000012718
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012719/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012720
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012721#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012722static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012723helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012724{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012725 unsigned col;
12726 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012727
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012728 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012729 "Built-in commands:\n"
12730 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012731 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012732 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012733 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012734 if (col > 60) {
12735 out1fmt("\n");
12736 col = 0;
12737 }
12738 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012739# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012740 {
12741 const char *a = applet_names;
12742 while (*a) {
12743 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12744 if (col > 60) {
12745 out1fmt("\n");
12746 col = 0;
12747 }
Ron Yorston2b919582016-04-08 11:57:20 +010012748 while (*a++ != '\0')
12749 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012750 }
12751 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012752# endif
Eric Andersenc470f442003-07-28 09:56:35 +000012753 out1fmt("\n\n");
12754 return EXIT_SUCCESS;
12755}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012756#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012757
Flemming Madsend96ffda2013-04-07 18:47:24 +020012758#if MAX_HISTORY
12759static int FAST_FUNC
12760historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12761{
12762 show_history(line_input_state);
12763 return EXIT_SUCCESS;
12764}
12765#endif
12766
Eric Andersencb57d552001-06-28 07:25:16 +000012767/*
Eric Andersencb57d552001-06-28 07:25:16 +000012768 * The export and readonly commands.
12769 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012770static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012771exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012772{
12773 struct var *vp;
12774 char *name;
12775 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012776 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012777 char opt;
12778 int flag;
12779 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012780
Denys Vlasenkod5275882012-10-01 13:41:17 +020012781 /* "readonly" in bash accepts, but ignores -n.
12782 * We do the same: it saves a conditional in nextopt's param.
12783 */
12784 flag_off = 0;
12785 while ((opt = nextopt("np")) != '\0') {
12786 if (opt == 'n')
12787 flag_off = VEXPORT;
12788 }
12789 flag = VEXPORT;
12790 if (argv[0][0] == 'r') {
12791 flag = VREADONLY;
12792 flag_off = 0; /* readonly ignores -n */
12793 }
12794 flag_off = ~flag_off;
12795
12796 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12797 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012798 aptr = argptr;
12799 name = *aptr;
12800 if (name) {
12801 do {
12802 p = strchr(name, '=');
12803 if (p != NULL) {
12804 p++;
12805 } else {
12806 vp = *findvar(hashvar(name), name);
12807 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012808 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012809 continue;
12810 }
Eric Andersencb57d552001-06-28 07:25:16 +000012811 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012812 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012813 } while ((name = *++aptr) != NULL);
12814 return 0;
12815 }
Eric Andersencb57d552001-06-28 07:25:16 +000012816 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012817
12818 /* No arguments. Show the list of exported or readonly vars.
12819 * -n is ignored.
12820 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012821 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012822 return 0;
12823}
12824
Eric Andersencb57d552001-06-28 07:25:16 +000012825/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012826 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012827 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012828static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012829unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012830{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012831 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012832
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012833 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012834 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012835 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012836}
12837
Eric Andersencb57d552001-06-28 07:25:16 +000012838/*
Eric Andersencb57d552001-06-28 07:25:16 +000012839 * The unset builtin command. We unset the function before we unset the
12840 * variable to allow a function to be unset when there is a readonly variable
12841 * with the same name.
12842 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012843static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012844unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012845{
12846 char **ap;
12847 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012848 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012849 int ret = 0;
12850
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012851 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012852 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012853 }
Eric Andersencb57d552001-06-28 07:25:16 +000012854
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012855 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012856 if (flag != 'f') {
12857 i = unsetvar(*ap);
12858 ret |= i;
12859 if (!(i & 2))
12860 continue;
12861 }
12862 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012863 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012864 }
Eric Andersenc470f442003-07-28 09:56:35 +000012865 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012866}
12867
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012868static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012869 ' ', offsetof(struct tms, tms_utime),
12870 '\n', offsetof(struct tms, tms_stime),
12871 ' ', offsetof(struct tms, tms_cutime),
12872 '\n', offsetof(struct tms, tms_cstime),
12873 0
12874};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012875static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012876timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012877{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012878 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012879 const unsigned char *p;
12880 struct tms buf;
12881
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012882 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012883 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012884
12885 p = timescmd_str;
12886 do {
12887 t = *(clock_t *)(((char *) &buf) + p[1]);
12888 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012889 t = t % clk_tck;
12890 out1fmt("%lum%lu.%03lus%c",
12891 s / 60, s % 60,
12892 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012893 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012894 p += 2;
12895 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012896
Eric Andersencb57d552001-06-28 07:25:16 +000012897 return 0;
12898}
12899
Mike Frysinger98c52642009-04-02 10:02:37 +000012900#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012901/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012902 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012903 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012904 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012905 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012906 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012907static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012908letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012909{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012910 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012911
Denis Vlasenko68404f12008-03-17 09:00:54 +000012912 argv++;
12913 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012914 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012915 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012916 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012917 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012918
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012919 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012920}
Eric Andersenc470f442003-07-28 09:56:35 +000012921#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012922
Eric Andersenc470f442003-07-28 09:56:35 +000012923/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012924 * The read builtin. Options:
12925 * -r Do not interpret '\' specially
12926 * -s Turn off echo (tty only)
12927 * -n NCHARS Read NCHARS max
12928 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12929 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12930 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012931 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012932 * TODO: bash also has:
12933 * -a ARRAY Read into array[0],[1],etc
12934 * -d DELIM End on DELIM char, not newline
12935 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012936 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012937static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012938readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012939{
Denys Vlasenko73067272010-01-12 22:11:24 +010012940 char *opt_n = NULL;
12941 char *opt_p = NULL;
12942 char *opt_t = NULL;
12943 char *opt_u = NULL;
12944 int read_flags = 0;
12945 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012946 int i;
12947
Denys Vlasenko73067272010-01-12 22:11:24 +010012948 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012949 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012950 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012951 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012952 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012953 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012954 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012955 break;
12956 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012957 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012958 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012959 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012960 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012961 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012962 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012963 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012964 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012965 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012966 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012967 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012968 default:
12969 break;
12970 }
Eric Andersenc470f442003-07-28 09:56:35 +000012971 }
Paul Fox02eb9342005-09-07 16:56:02 +000012972
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012973 /* "read -s" needs to save/restore termios, can't allow ^C
12974 * to jump out of it.
12975 */
12976 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012977 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010012978 argptr,
12979 bltinlookup("IFS"), /* can be NULL */
12980 read_flags,
12981 opt_n,
12982 opt_p,
12983 opt_t,
12984 opt_u
12985 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012986 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012987
Denys Vlasenko73067272010-01-12 22:11:24 +010012988 if ((uintptr_t)r > 1)
12989 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012990
Denys Vlasenko73067272010-01-12 22:11:24 +010012991 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012992}
12993
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012994static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020012995umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012996{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012997 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000012998
Eric Andersenc470f442003-07-28 09:56:35 +000012999 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013000 int symbolic_mode = 0;
13001
13002 while (nextopt("S") != '\0') {
13003 symbolic_mode = 1;
13004 }
13005
Denis Vlasenkob012b102007-02-19 22:43:01 +000013006 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013007 mask = umask(0);
13008 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013009 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013010
Denys Vlasenko6283f982015-10-07 16:56:20 +020013011 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013012 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013013 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013014 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013015 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013016
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013017 i = 2;
13018 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013019 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013020 *p++ = permuser[i];
13021 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013022 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013023 if (!(mask & 0400)) *p++ = 'r';
13024 if (!(mask & 0200)) *p++ = 'w';
13025 if (!(mask & 0100)) *p++ = 'x';
13026 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013027 if (--i < 0)
13028 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013029 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013030 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013031 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013032 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013033 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013034 }
13035 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013036 char *modestr = *argptr;
13037 /* numeric umasks are taken as-is */
13038 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13039 if (!isdigit(modestr[0]))
13040 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013041 mask = bb_parse_mode(modestr, mask);
13042 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013043 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013044 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013045 if (!isdigit(modestr[0]))
13046 mask ^= 0777;
13047 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013048 }
13049 return 0;
13050}
13051
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013052static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013053ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013054{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013055 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013056}
13057
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013058/* ============ main() and helpers */
13059
13060/*
13061 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013062 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013063static void
13064exitshell(void)
13065{
13066 struct jmploc loc;
13067 char *p;
13068 int status;
13069
Denys Vlasenkobede2152011-09-04 16:12:33 +020013070#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13071 save_history(line_input_state);
13072#endif
13073
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013074 status = exitstatus;
13075 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13076 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013077 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013078/* dash bug: it just does _exit(exitstatus) here
13079 * but we have to do setjobctl(0) first!
13080 * (bug is still not fixed in dash-0.5.3 - if you run dash
13081 * under Midnight Commander, on exit from dash MC is backgrounded) */
13082 status = exitstatus;
13083 goto out;
13084 }
13085 exception_handler = &loc;
13086 p = trap[0];
13087 if (p) {
13088 trap[0] = NULL;
13089 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020013090 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013091 }
13092 flush_stdout_stderr();
13093 out:
13094 setjobctl(0);
13095 _exit(status);
13096 /* NOTREACHED */
13097}
13098
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013099static void
13100init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013101{
13102 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013103 /* we will never free this */
13104 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013105
13106 /* from trap.c: */
13107 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013108 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13109 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13110 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013111 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013112
13113 /* from var.c: */
13114 {
13115 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013116 const char *p;
13117 struct stat st1, st2;
13118
13119 initvar();
13120 for (envp = environ; envp && *envp; envp++) {
Denys Vlasenkob6838b52016-09-30 11:33:47 +020013121 p = endofname(*envp);
13122 if (p != *envp && *p == '=') {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013123 setvareq(*envp, VEXPORT|VTEXTFIXED);
13124 }
13125 }
13126
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013127 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013128#if ENABLE_ASH_BASH_COMPAT
13129 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013130 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013131 if (!lookupvar("HOSTNAME")) {
13132 struct utsname uts;
13133 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013134 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013135 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013136#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013137 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013138 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013139 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013140 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13141 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013142 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013143 }
13144 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013145 setpwd(p, 0);
13146 }
13147}
13148
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013149
13150//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013151//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013152//usage:#define ash_full_usage "\n\n"
13153//usage: "Unix shell interpreter"
13154
13155//usage:#if ENABLE_FEATURE_SH_IS_ASH
13156//usage:# define sh_trivial_usage ash_trivial_usage
13157//usage:# define sh_full_usage ash_full_usage
13158//usage:#endif
13159//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13160//usage:# define bash_trivial_usage ash_trivial_usage
13161//usage:# define bash_full_usage ash_full_usage
13162//usage:#endif
13163
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013164/*
13165 * Process the shell command line arguments.
13166 */
13167static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013168procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013169{
13170 int i;
13171 const char *xminusc;
13172 char **xargv;
13173
13174 xargv = argv;
13175 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013176 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013177 xargv++;
13178 for (i = 0; i < NOPTS; i++)
13179 optlist[i] = 2;
13180 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013181 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013182 /* it already printed err message */
13183 raise_exception(EXERROR);
13184 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013185 xargv = argptr;
13186 xminusc = minusc;
13187 if (*xargv == NULL) {
13188 if (xminusc)
13189 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13190 sflag = 1;
13191 }
13192 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13193 iflag = 1;
13194 if (mflag == 2)
13195 mflag = iflag;
13196 for (i = 0; i < NOPTS; i++)
13197 if (optlist[i] == 2)
13198 optlist[i] = 0;
13199#if DEBUG == 2
13200 debug = 1;
13201#endif
13202 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13203 if (xminusc) {
13204 minusc = *xargv++;
13205 if (*xargv)
13206 goto setarg0;
13207 } else if (!sflag) {
13208 setinputfile(*xargv, 0);
13209 setarg0:
13210 arg0 = *xargv++;
13211 commandname = arg0;
13212 }
13213
13214 shellparam.p = xargv;
13215#if ENABLE_ASH_GETOPTS
13216 shellparam.optind = 1;
13217 shellparam.optoff = -1;
13218#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013219 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013220 while (*xargv) {
13221 shellparam.nparam++;
13222 xargv++;
13223 }
13224 optschanged();
13225}
13226
13227/*
13228 * Read /etc/profile or .profile.
13229 */
13230static void
13231read_profile(const char *name)
13232{
13233 int skip;
13234
13235 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13236 return;
13237 skip = cmdloop(0);
13238 popfile();
13239 if (skip)
13240 exitshell();
13241}
13242
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013243/*
13244 * This routine is called when an error or an interrupt occurs in an
13245 * interactive shell and control is returned to the main command loop.
13246 */
13247static void
13248reset(void)
13249{
13250 /* from eval.c: */
13251 evalskip = 0;
13252 loopnest = 0;
13253 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013254 g_parsefile->left_in_buffer = 0;
13255 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013256 popallfiles();
13257 /* from parser.c: */
13258 tokpushback = 0;
13259 checkkwd = 0;
13260 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013261 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013262}
13263
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013264#if PROFILE
13265static short profile_buf[16384];
13266extern int etext();
13267#endif
13268
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013269/*
13270 * Main routine. We initialize things, parse the arguments, execute
13271 * profiles if we're a login shell, and then call cmdloop to execute
13272 * commands. The setjmp call sets up the location to jump to when an
13273 * exception occurs. When an exception occurs the variable "state"
13274 * is used to figure out how far we had gotten.
13275 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013276int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013277int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013278{
Mike Frysinger98c52642009-04-02 10:02:37 +000013279 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013280 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013281 struct jmploc jmploc;
13282 struct stackmark smark;
13283
Denis Vlasenko01631112007-12-16 17:20:38 +000013284 /* Initialize global data */
13285 INIT_G_misc();
13286 INIT_G_memstack();
13287 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013288#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013289 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013290#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013291 INIT_G_cmdtable();
13292
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013293#if PROFILE
13294 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13295#endif
13296
13297#if ENABLE_FEATURE_EDITING
13298 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13299#endif
13300 state = 0;
13301 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013302 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013303 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013304
13305 reset();
13306
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013307 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013308 if (e == EXERROR)
13309 exitstatus = 2;
13310 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013311 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013312 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013313 }
13314 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013315 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013316 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013317
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013318 popstackmark(&smark);
13319 FORCE_INT_ON; /* enable interrupts */
13320 if (s == 1)
13321 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013322 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013323 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013324 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013325 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013326 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013327 }
13328 exception_handler = &jmploc;
13329#if DEBUG
13330 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013331 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013332 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013333#endif
13334 rootpid = getpid();
13335
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013336 init();
13337 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013338 procargs(argv);
13339
Denys Vlasenko6088e132010-12-25 23:58:42 +010013340 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013341 isloginsh = 1;
13342 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013343 const char *hp;
13344
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013345 state = 1;
13346 read_profile("/etc/profile");
13347 state1:
13348 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013349 hp = lookupvar("HOME");
13350 if (hp) {
13351 hp = concat_path_file(hp, ".profile");
13352 read_profile(hp);
13353 free((char*)hp);
13354 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013355 }
13356 state2:
13357 state = 3;
13358 if (
13359#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013360 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013361#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013362 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013363 ) {
13364 shinit = lookupvar("ENV");
13365 if (shinit != NULL && *shinit != '\0') {
13366 read_profile(shinit);
13367 }
13368 }
13369 state3:
13370 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013371 if (minusc) {
13372 /* evalstring pushes parsefile stack.
13373 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013374 * is one of stacked source fds.
13375 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013376 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013377 // ^^ not necessary since now we special-case fd 0
13378 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013379 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013380 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013381
13382 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013383#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013384 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013385 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013386 if (!hp) {
13387 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013388 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013389 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013390 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013391 free((char*)hp);
13392 hp = lookupvar("HISTFILE");
13393 }
13394 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013395 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013396 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013397# if ENABLE_FEATURE_SH_HISTFILESIZE
13398 hp = lookupvar("HISTFILESIZE");
13399 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13400# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013401 }
13402#endif
13403 state4: /* XXX ??? - why isn't this before the "if" statement */
13404 cmdloop(1);
13405 }
13406#if PROFILE
13407 monitor(0);
13408#endif
13409#ifdef GPROF
13410 {
13411 extern void _mcleanup(void);
13412 _mcleanup();
13413 }
13414#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013415 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013416 exitshell();
13417 /* NOTREACHED */
13418}
13419
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013420
Eric Andersendf82f612001-06-28 07:46:40 +000013421/*-
13422 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013423 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013424 *
13425 * This code is derived from software contributed to Berkeley by
13426 * Kenneth Almquist.
13427 *
13428 * Redistribution and use in source and binary forms, with or without
13429 * modification, are permitted provided that the following conditions
13430 * are met:
13431 * 1. Redistributions of source code must retain the above copyright
13432 * notice, this list of conditions and the following disclaimer.
13433 * 2. Redistributions in binary form must reproduce the above copyright
13434 * notice, this list of conditions and the following disclaimer in the
13435 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013436 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013437 * may be used to endorse or promote products derived from this software
13438 * without specific prior written permission.
13439 *
13440 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13441 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13442 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13443 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13444 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13445 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13446 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13447 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13448 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13449 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13450 * SUCH DAMAGE.
13451 */