blob: f7ce698a38c9d9d7bdc55bc3922e9781b55b435b [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 *oldstackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001542 struct stack_block *sp;
1543 struct stack_block *prevstackp;
1544 size_t grosslen;
1545
1546 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001547 oldstackp = g_stackp;
1548 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001549 prevstackp = sp->prev;
1550 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1551 sp = ckrealloc(sp, grosslen);
1552 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001553 g_stackp = sp;
1554 g_stacknxt = sp->space;
1555 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001556 sstrend = sp->space + newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001557 INT_ON;
1558 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001559 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001560 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001561 char *p = stalloc(newlen);
1562
1563 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001564 g_stacknxt = memcpy(p, oldspace, oldlen);
1565 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001566 }
1567}
1568
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001569/*
1570 * The following routines are somewhat easier to use than the above.
1571 * The user declares a variable of type STACKSTR, which may be declared
1572 * to be a register. The macro STARTSTACKSTR initializes things. Then
1573 * the user uses the macro STPUTC to add characters to the string. In
1574 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1575 * grown as necessary. When the user is done, she can just leave the
1576 * string there and refer to it using stackblock(). Or she can allocate
1577 * the space for it using grabstackstr(). If it is necessary to allow
1578 * someone else to use the stack temporarily and then continue to grow
1579 * the string, the user should use grabstack to allocate the space, and
1580 * then call ungrabstr(p) to return to the previous mode of operation.
1581 *
1582 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1583 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1584 * is space for at least one character.
1585 */
1586static void *
1587growstackstr(void)
1588{
1589 size_t len = stackblocksize();
1590 if (herefd >= 0 && len >= 1024) {
1591 full_write(herefd, stackblock(), len);
1592 return stackblock();
1593 }
1594 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001595 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001596}
1597
1598/*
1599 * Called from CHECKSTRSPACE.
1600 */
1601static char *
1602makestrspace(size_t newlen, char *p)
1603{
Denis Vlasenko01631112007-12-16 17:20:38 +00001604 size_t len = p - g_stacknxt;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001605 size_t size = stackblocksize();
1606
1607 for (;;) {
1608 size_t nleft;
1609
1610 size = stackblocksize();
1611 nleft = size - len;
1612 if (nleft >= newlen)
1613 break;
1614 growstackblock();
1615 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001616 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001617}
1618
1619static char *
1620stack_nputstr(const char *s, size_t n, char *p)
1621{
1622 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001623 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001624 return p;
1625}
1626
1627static char *
1628stack_putstr(const char *s, char *p)
1629{
1630 return stack_nputstr(s, strlen(s), p);
1631}
1632
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001633static char *
1634_STPUTC(int c, char *p)
1635{
1636 if (p == sstrend)
1637 p = growstackstr();
1638 *p++ = c;
1639 return p;
1640}
1641
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001642#define STARTSTACKSTR(p) ((p) = stackblock())
1643#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001644#define CHECKSTRSPACE(n, p) do { \
1645 char *q = (p); \
1646 size_t l = (n); \
1647 size_t m = sstrend - q; \
1648 if (l > m) \
1649 (p) = makestrspace(l, q); \
1650} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001651#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001652#define STACKSTRNUL(p) do { \
1653 if ((p) == sstrend) \
1654 (p) = growstackstr(); \
1655 *(p) = '\0'; \
1656} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001657#define STUNPUTC(p) (--(p))
1658#define STTOPC(p) ((p)[-1])
1659#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001660
1661#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001662#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001663#define stackstrend() ((void *)sstrend)
1664
1665
1666/* ============ String helpers */
1667
1668/*
1669 * prefix -- see if pfx is a prefix of string.
1670 */
1671static char *
1672prefix(const char *string, const char *pfx)
1673{
1674 while (*pfx) {
1675 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001676 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001677 }
1678 return (char *) string;
1679}
1680
1681/*
1682 * Check for a valid number. This should be elsewhere.
1683 */
1684static int
1685is_number(const char *p)
1686{
1687 do {
1688 if (!isdigit(*p))
1689 return 0;
1690 } while (*++p != '\0');
1691 return 1;
1692}
1693
1694/*
1695 * Convert a string of digits to an integer, printing an error message on
1696 * failure.
1697 */
1698static int
1699number(const char *s)
1700{
1701 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001702 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001703 return atoi(s);
1704}
1705
1706/*
1707 * Produce a possibly single quoted string suitable as input to the shell.
1708 * The return string is allocated on the stack.
1709 */
1710static char *
1711single_quote(const char *s)
1712{
1713 char *p;
1714
1715 STARTSTACKSTR(p);
1716
1717 do {
1718 char *q;
1719 size_t len;
1720
1721 len = strchrnul(s, '\'') - s;
1722
1723 q = p = makestrspace(len + 3, p);
1724
1725 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001726 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001727 *q++ = '\'';
1728 s += len;
1729
1730 STADJUST(q - p, p);
1731
Denys Vlasenkocd716832009-11-28 22:14:02 +01001732 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001733 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001734 len = 0;
1735 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001736
1737 q = p = makestrspace(len + 3, p);
1738
1739 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001740 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001741 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001742
1743 STADJUST(q - p, p);
1744 } while (*s);
1745
Denys Vlasenkocd716832009-11-28 22:14:02 +01001746 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001747
1748 return stackblock();
1749}
1750
1751
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001752/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001753
1754static char **argptr; /* argument list for builtin commands */
1755static char *optionarg; /* set by nextopt (like getopt) */
1756static char *optptr; /* used by nextopt */
1757
1758/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001759 * XXX - should get rid of. Have all builtins use getopt(3).
1760 * The library getopt must have the BSD extension static variable
1761 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001762 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001763 * Standard option processing (a la getopt) for builtin routines.
1764 * The only argument that is passed to nextopt is the option string;
1765 * the other arguments are unnecessary. It returns the character,
1766 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001767 */
1768static int
1769nextopt(const char *optstring)
1770{
1771 char *p;
1772 const char *q;
1773 char c;
1774
1775 p = optptr;
1776 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001777 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001778 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001779 if (p == NULL)
1780 return '\0';
1781 if (*p != '-')
1782 return '\0';
1783 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001784 return '\0';
1785 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001786 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001787 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001788 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001789 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001790 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001792 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001793 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001794 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001795 if (*++q == ':')
1796 q++;
1797 }
1798 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001799 if (*p == '\0') {
1800 p = *argptr++;
1801 if (p == NULL)
1802 ash_msg_and_raise_error("no arg for -%c option", c);
1803 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001804 optionarg = p;
1805 p = NULL;
1806 }
1807 optptr = p;
1808 return c;
1809}
1810
1811
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001812/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001813
Denis Vlasenko01631112007-12-16 17:20:38 +00001814/*
1815 * The parsefile structure pointed to by the global variable parsefile
1816 * contains information about the current file being read.
1817 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001818struct shparam {
1819 int nparam; /* # of positional parameters (without $0) */
1820#if ENABLE_ASH_GETOPTS
1821 int optind; /* next parameter to be processed by getopts */
1822 int optoff; /* used by getopts */
1823#endif
1824 unsigned char malloced; /* if parameter list dynamically allocated */
1825 char **p; /* parameter list */
1826};
1827
1828/*
1829 * Free the list of positional parameters.
1830 */
1831static void
1832freeparam(volatile struct shparam *param)
1833{
Denis Vlasenko01631112007-12-16 17:20:38 +00001834 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001835 char **ap, **ap1;
1836 ap = ap1 = param->p;
1837 while (*ap)
1838 free(*ap++);
1839 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001840 }
1841}
1842
1843#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001844static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001845#endif
1846
1847struct var {
1848 struct var *next; /* next entry in hash list */
1849 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001850 const char *var_text; /* name=value */
1851 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001852 /* the variable gets set/unset */
1853};
1854
1855struct localvar {
1856 struct localvar *next; /* next local variable in list */
1857 struct var *vp; /* the variable that was made local */
1858 int flags; /* saved flags */
1859 const char *text; /* saved text */
1860};
1861
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001862/* flags */
1863#define VEXPORT 0x01 /* variable is exported */
1864#define VREADONLY 0x02 /* variable cannot be modified */
1865#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1866#define VTEXTFIXED 0x08 /* text is statically allocated */
1867#define VSTACK 0x10 /* text is allocated on the stack */
1868#define VUNSET 0x20 /* the variable is not set */
1869#define VNOFUNC 0x40 /* don't call the callback function */
1870#define VNOSET 0x80 /* do not set variable - just readonly test */
1871#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001872#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001873# define VDYNAMIC 0x200 /* dynamic variable */
1874#else
1875# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001876#endif
1877
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001878
Denis Vlasenko01631112007-12-16 17:20:38 +00001879/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001880#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001881static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001882change_lc_all(const char *value)
1883{
1884 if (value && *value != '\0')
1885 setlocale(LC_ALL, value);
1886}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001887static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001888change_lc_ctype(const char *value)
1889{
1890 if (value && *value != '\0')
1891 setlocale(LC_CTYPE, value);
1892}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001893#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001894#if ENABLE_ASH_MAIL
1895static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001896static void changemail(const char *var_value) FAST_FUNC;
1897#else
1898# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001899#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001900static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001901#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001902static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001903#endif
1904
Denis Vlasenko01631112007-12-16 17:20:38 +00001905static const struct {
1906 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001907 const char *var_text;
1908 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001909} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001910 /*
1911 * Note: VEXPORT would not work correctly here for NOFORK applets:
1912 * some environment strings may be constant.
1913 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001914 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001915#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001916 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1917 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001918#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001919 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1920 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1921 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1922 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001923#if ENABLE_ASH_GETOPTS
Denis Vlasenko01631112007-12-16 17:20:38 +00001924 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001925#endif
1926#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001927 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001928#endif
1929#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001930 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1931 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001932#endif
1933#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001934 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001935#endif
1936};
1937
Denis Vlasenko0b769642008-07-24 07:54:57 +00001938struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001939
1940struct globals_var {
1941 struct shparam shellparam; /* $@ current positional parameters */
1942 struct redirtab *redirlist;
1943 int g_nullredirs;
1944 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1945 struct var *vartab[VTABSIZE];
1946 struct var varinit[ARRAY_SIZE(varinit_data)];
1947};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001948extern struct globals_var *const ash_ptr_to_globals_var;
1949#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001950#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001951//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001952#define g_nullredirs (G_var.g_nullredirs )
1953#define preverrout_fd (G_var.preverrout_fd)
1954#define vartab (G_var.vartab )
1955#define varinit (G_var.varinit )
1956#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001957 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001958 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1959 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001960 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001961 varinit[i].flags = varinit_data[i].flags; \
1962 varinit[i].var_text = varinit_data[i].var_text; \
1963 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001964 } \
1965} while (0)
1966
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001967#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001968#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001969# define vmail (&vifs)[1]
1970# define vmpath (&vmail)[1]
1971# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001972#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001973# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001974#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001975#define vps1 (&vpath)[1]
1976#define vps2 (&vps1)[1]
1977#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001978#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001979# define voptind (&vps4)[1]
1980# if ENABLE_ASH_RANDOM_SUPPORT
1981# define vrandom (&voptind)[1]
1982# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001983#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001984# if ENABLE_ASH_RANDOM_SUPPORT
1985# define vrandom (&vps4)[1]
1986# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001987#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001988
1989/*
1990 * The following macros access the values of the above variables.
1991 * They have to skip over the name. They return the null string
1992 * for unset variables.
1993 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001994#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001995#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001996#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001997# define mailval() (vmail.var_text + 5)
1998# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001999# define mpathset() ((vmpath.flags & VUNSET) == 0)
2000#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002001#define pathval() (vpath.var_text + 5)
2002#define ps1val() (vps1.var_text + 4)
2003#define ps2val() (vps2.var_text + 4)
2004#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002005#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002006# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002007#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002008
Denis Vlasenko01631112007-12-16 17:20:38 +00002009#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002010static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002011getoptsreset(const char *value)
2012{
2013 shellparam.optind = number(value);
2014 shellparam.optoff = -1;
2015}
2016#endif
2017
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002018/*
2019 * Compares two strings up to the first = or '\0'. The first
2020 * string must be terminated by '='; the second may be terminated by
2021 * either '=' or '\0'.
2022 */
2023static int
2024varcmp(const char *p, const char *q)
2025{
2026 int c, d;
2027
2028 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002029 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002030 goto out;
2031 p++;
2032 q++;
2033 }
2034 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002035 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002036 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002037 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002038 out:
2039 return c - d;
2040}
2041
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002042/*
2043 * Find the appropriate entry in the hash table from the name.
2044 */
2045static struct var **
2046hashvar(const char *p)
2047{
2048 unsigned hashval;
2049
2050 hashval = ((unsigned char) *p) << 4;
2051 while (*p && *p != '=')
2052 hashval += (unsigned char) *p++;
2053 return &vartab[hashval % VTABSIZE];
2054}
2055
2056static int
2057vpcmp(const void *a, const void *b)
2058{
2059 return varcmp(*(const char **)a, *(const char **)b);
2060}
2061
2062/*
2063 * This routine initializes the builtin variables.
2064 */
2065static void
2066initvar(void)
2067{
2068 struct var *vp;
2069 struct var *end;
2070 struct var **vpp;
2071
2072 /*
2073 * PS1 depends on uid
2074 */
2075#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002076 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002077#else
2078 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002079 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002080#endif
2081 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002082 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002083 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002084 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002085 vp->next = *vpp;
2086 *vpp = vp;
2087 } while (++vp < end);
2088}
2089
2090static struct var **
2091findvar(struct var **vpp, const char *name)
2092{
2093 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002094 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002095 break;
2096 }
2097 }
2098 return vpp;
2099}
2100
2101/*
2102 * Find the value of a variable. Returns NULL if not set.
2103 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002104static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002105lookupvar(const char *name)
2106{
2107 struct var *v;
2108
2109 v = *findvar(hashvar(name), name);
2110 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002111#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002112 /*
2113 * Dynamic variables are implemented roughly the same way they are
2114 * in bash. Namely, they're "special" so long as they aren't unset.
2115 * As soon as they're unset, they're no longer dynamic, and dynamic
2116 * lookup will no longer happen at that point. -- PFM.
2117 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002118 if (v->flags & VDYNAMIC)
2119 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002120#endif
2121 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002122 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002123 }
2124 return NULL;
2125}
2126
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002127static void reinit_unicode_for_ash(void)
2128{
2129 /* Unicode support should be activated even if LANG is set
2130 * _during_ shell execution, not only if it was set when
2131 * shell was started. Therefore, re-check LANG every time:
2132 */
2133 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2134 || ENABLE_UNICODE_USING_LOCALE
2135 ) {
2136 const char *s = lookupvar("LC_ALL");
2137 if (!s) s = lookupvar("LC_CTYPE");
2138 if (!s) s = lookupvar("LANG");
2139 reinit_unicode(s);
2140 }
2141}
2142
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002143/*
2144 * Search the environment of a builtin command.
2145 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002146static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002147bltinlookup(const char *name)
2148{
2149 struct strlist *sp;
2150
2151 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002152 if (varcmp(sp->text, name) == 0)
2153 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002154 }
2155 return lookupvar(name);
2156}
2157
2158/*
2159 * Same as setvar except that the variable and value are passed in
2160 * the first argument as name=value. Since the first argument will
2161 * be actually stored in the table, it should not be a string that
2162 * will go away.
2163 * Called with interrupts off.
2164 */
2165static void
2166setvareq(char *s, int flags)
2167{
2168 struct var *vp, **vpp;
2169
2170 vpp = hashvar(s);
2171 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2172 vp = *findvar(vpp, s);
2173 if (vp) {
2174 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2175 const char *n;
2176
2177 if (flags & VNOSAVE)
2178 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002179 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002180 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2181 }
2182
2183 if (flags & VNOSET)
2184 return;
2185
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002186 if (vp->var_func && !(flags & VNOFUNC))
2187 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002188
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002189 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2190 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002191
2192 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2193 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002194 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002195 if (flags & VNOSET)
2196 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002197 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002198 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002199 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002200 *vpp = vp;
2201 }
2202 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2203 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002204 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002205 vp->flags = flags;
2206}
2207
2208/*
2209 * Set the value of a variable. The flags argument is ored with the
2210 * flags of the variable. If val is NULL, the variable is unset.
2211 */
2212static void
2213setvar(const char *name, const char *val, int flags)
2214{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002215 const char *q;
2216 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002217 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002218 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002219 size_t vallen;
2220
2221 q = endofname(name);
2222 p = strchrnul(q, '=');
2223 namelen = p - name;
2224 if (!namelen || p != q)
2225 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2226 vallen = 0;
2227 if (val == NULL) {
2228 flags |= VUNSET;
2229 } else {
2230 vallen = strlen(val);
2231 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002232
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002233 INT_OFF;
2234 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002235 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236 if (val) {
2237 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002238 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002239 }
2240 *p = '\0';
2241 setvareq(nameeq, flags | VNOSAVE);
2242 INT_ON;
2243}
2244
Denys Vlasenko03dad222010-01-12 23:29:57 +01002245static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002246setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002247{
2248 setvar(name, val, 0);
2249}
2250
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002251#if ENABLE_ASH_GETOPTS
2252/*
2253 * Safe version of setvar, returns 1 on success 0 on failure.
2254 */
2255static int
2256setvarsafe(const char *name, const char *val, int flags)
2257{
2258 int err;
2259 volatile int saveint;
2260 struct jmploc *volatile savehandler = exception_handler;
2261 struct jmploc jmploc;
2262
2263 SAVE_INT(saveint);
2264 if (setjmp(jmploc.loc))
2265 err = 1;
2266 else {
2267 exception_handler = &jmploc;
2268 setvar(name, val, flags);
2269 err = 0;
2270 }
2271 exception_handler = savehandler;
2272 RESTORE_INT(saveint);
2273 return err;
2274}
2275#endif
2276
2277/*
2278 * Unset the specified variable.
2279 */
2280static int
2281unsetvar(const char *s)
2282{
2283 struct var **vpp;
2284 struct var *vp;
2285 int retval;
2286
2287 vpp = findvar(hashvar(s), s);
2288 vp = *vpp;
2289 retval = 2;
2290 if (vp) {
2291 int flags = vp->flags;
2292
2293 retval = 1;
2294 if (flags & VREADONLY)
2295 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002296#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002297 vp->flags &= ~VDYNAMIC;
2298#endif
2299 if (flags & VUNSET)
2300 goto ok;
2301 if ((flags & VSTRFIXED) == 0) {
2302 INT_OFF;
2303 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002304 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002305 *vpp = vp->next;
2306 free(vp);
2307 INT_ON;
2308 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002309 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002310 vp->flags &= ~VEXPORT;
2311 }
2312 ok:
2313 retval = 0;
2314 }
2315 out:
2316 return retval;
2317}
2318
2319/*
2320 * Process a linked list of variable assignments.
2321 */
2322static void
2323listsetvar(struct strlist *list_set_var, int flags)
2324{
2325 struct strlist *lp = list_set_var;
2326
2327 if (!lp)
2328 return;
2329 INT_OFF;
2330 do {
2331 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002332 lp = lp->next;
2333 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002334 INT_ON;
2335}
2336
2337/*
2338 * Generate a list of variables satisfying the given conditions.
2339 */
2340static char **
2341listvars(int on, int off, char ***end)
2342{
2343 struct var **vpp;
2344 struct var *vp;
2345 char **ep;
2346 int mask;
2347
2348 STARTSTACKSTR(ep);
2349 vpp = vartab;
2350 mask = on | off;
2351 do {
2352 for (vp = *vpp; vp; vp = vp->next) {
2353 if ((vp->flags & mask) == on) {
2354 if (ep == stackstrend())
2355 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002356 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002357 }
2358 }
2359 } while (++vpp < vartab + VTABSIZE);
2360 if (ep == stackstrend())
2361 ep = growstackstr();
2362 if (end)
2363 *end = ep;
2364 *ep++ = NULL;
2365 return grabstackstr(ep);
2366}
2367
2368
2369/* ============ Path search helper
2370 *
2371 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002372 * of the path before the first call; path_advance will update
2373 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002374 * the possible path expansions in sequence. If an option (indicated by
2375 * a percent sign) appears in the path entry then the global variable
2376 * pathopt will be set to point to it; otherwise pathopt will be set to
2377 * NULL.
2378 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002379static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002380
2381static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002382path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002383{
2384 const char *p;
2385 char *q;
2386 const char *start;
2387 size_t len;
2388
2389 if (*path == NULL)
2390 return NULL;
2391 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002392 for (p = start; *p && *p != ':' && *p != '%'; p++)
2393 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002394 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2395 while (stackblocksize() < len)
2396 growstackblock();
2397 q = stackblock();
2398 if (p != start) {
2399 memcpy(q, start, p - start);
2400 q += p - start;
2401 *q++ = '/';
2402 }
2403 strcpy(q, name);
2404 pathopt = NULL;
2405 if (*p == '%') {
2406 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002407 while (*p && *p != ':')
2408 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002409 }
2410 if (*p == ':')
2411 *path = p + 1;
2412 else
2413 *path = NULL;
2414 return stalloc(len);
2415}
2416
2417
2418/* ============ Prompt */
2419
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002420static smallint doprompt; /* if set, prompt the user */
2421static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002422
2423#if ENABLE_FEATURE_EDITING
2424static line_input_t *line_input_state;
2425static const char *cmdedit_prompt;
2426static void
2427putprompt(const char *s)
2428{
2429 if (ENABLE_ASH_EXPAND_PRMT) {
2430 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002431 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002432 return;
2433 }
2434 cmdedit_prompt = s;
2435}
2436#else
2437static void
2438putprompt(const char *s)
2439{
2440 out2str(s);
2441}
2442#endif
2443
2444#if ENABLE_ASH_EXPAND_PRMT
2445/* expandstr() needs parsing machinery, so it is far away ahead... */
2446static const char *expandstr(const char *ps);
2447#else
2448#define expandstr(s) s
2449#endif
2450
2451static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002452setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002453{
2454 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002455 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2456
2457 if (!do_set)
2458 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002459
2460 needprompt = 0;
2461
2462 switch (whichprompt) {
2463 case 1:
2464 prompt = ps1val();
2465 break;
2466 case 2:
2467 prompt = ps2val();
2468 break;
2469 default: /* 0 */
2470 prompt = nullstr;
2471 }
2472#if ENABLE_ASH_EXPAND_PRMT
Denys Vlasenko60ca8342016-09-30 11:21:21 +02002473 pushstackmark(&smark, stackblocksize());
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002474#endif
2475 putprompt(expandstr(prompt));
2476#if ENABLE_ASH_EXPAND_PRMT
2477 popstackmark(&smark);
2478#endif
2479}
2480
2481
2482/* ============ The cd and pwd commands */
2483
2484#define CD_PHYSICAL 1
2485#define CD_PRINT 2
2486
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002487static int
2488cdopt(void)
2489{
2490 int flags = 0;
2491 int i, j;
2492
2493 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002494 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002495 if (i != j) {
2496 flags ^= CD_PHYSICAL;
2497 j = i;
2498 }
2499 }
2500
2501 return flags;
2502}
2503
2504/*
2505 * Update curdir (the name of the current directory) in response to a
2506 * cd command.
2507 */
2508static const char *
2509updatepwd(const char *dir)
2510{
2511 char *new;
2512 char *p;
2513 char *cdcomppath;
2514 const char *lim;
2515
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002516 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002517 STARTSTACKSTR(new);
2518 if (*dir != '/') {
2519 if (curdir == nullstr)
2520 return 0;
2521 new = stack_putstr(curdir, new);
2522 }
2523 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002524 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002525 if (*dir != '/') {
2526 if (new[-1] != '/')
2527 USTPUTC('/', new);
2528 if (new > lim && *lim == '/')
2529 lim++;
2530 } else {
2531 USTPUTC('/', new);
2532 cdcomppath++;
2533 if (dir[1] == '/' && dir[2] != '/') {
2534 USTPUTC('/', new);
2535 cdcomppath++;
2536 lim++;
2537 }
2538 }
2539 p = strtok(cdcomppath, "/");
2540 while (p) {
2541 switch (*p) {
2542 case '.':
2543 if (p[1] == '.' && p[2] == '\0') {
2544 while (new > lim) {
2545 STUNPUTC(new);
2546 if (new[-1] == '/')
2547 break;
2548 }
2549 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002550 }
2551 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002552 break;
2553 /* fall through */
2554 default:
2555 new = stack_putstr(p, new);
2556 USTPUTC('/', new);
2557 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002558 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002559 }
2560 if (new > lim)
2561 STUNPUTC(new);
2562 *new = 0;
2563 return stackblock();
2564}
2565
2566/*
2567 * Find out what the current directory is. If we already know the current
2568 * directory, this routine returns immediately.
2569 */
2570static char *
2571getpwd(void)
2572{
Denis Vlasenko01631112007-12-16 17:20:38 +00002573 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002574 return dir ? dir : nullstr;
2575}
2576
2577static void
2578setpwd(const char *val, int setold)
2579{
2580 char *oldcur, *dir;
2581
2582 oldcur = dir = curdir;
2583
2584 if (setold) {
2585 setvar("OLDPWD", oldcur, VEXPORT);
2586 }
2587 INT_OFF;
2588 if (physdir != nullstr) {
2589 if (physdir != oldcur)
2590 free(physdir);
2591 physdir = nullstr;
2592 }
2593 if (oldcur == val || !val) {
2594 char *s = getpwd();
2595 physdir = s;
2596 if (!val)
2597 dir = s;
2598 } else
2599 dir = ckstrdup(val);
2600 if (oldcur != dir && oldcur != nullstr) {
2601 free(oldcur);
2602 }
2603 curdir = dir;
2604 INT_ON;
2605 setvar("PWD", dir, VEXPORT);
2606}
2607
2608static void hashcd(void);
2609
2610/*
2611 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2612 * know that the current directory has changed.
2613 */
2614static int
2615docd(const char *dest, int flags)
2616{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002617 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002618 int err;
2619
2620 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2621
2622 INT_OFF;
2623 if (!(flags & CD_PHYSICAL)) {
2624 dir = updatepwd(dest);
2625 if (dir)
2626 dest = dir;
2627 }
2628 err = chdir(dest);
2629 if (err)
2630 goto out;
2631 setpwd(dir, 1);
2632 hashcd();
2633 out:
2634 INT_ON;
2635 return err;
2636}
2637
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002638static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002639cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002640{
2641 const char *dest;
2642 const char *path;
2643 const char *p;
2644 char c;
2645 struct stat statb;
2646 int flags;
2647
2648 flags = cdopt();
2649 dest = *argptr;
2650 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002651 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002652 else if (LONE_DASH(dest)) {
2653 dest = bltinlookup("OLDPWD");
2654 flags |= CD_PRINT;
2655 }
2656 if (!dest)
2657 dest = nullstr;
2658 if (*dest == '/')
2659 goto step7;
2660 if (*dest == '.') {
2661 c = dest[1];
2662 dotdot:
2663 switch (c) {
2664 case '\0':
2665 case '/':
2666 goto step6;
2667 case '.':
2668 c = dest[2];
2669 if (c != '.')
2670 goto dotdot;
2671 }
2672 }
2673 if (!*dest)
2674 dest = ".";
2675 path = bltinlookup("CDPATH");
2676 if (!path) {
2677 step6:
2678 step7:
2679 p = dest;
2680 goto docd;
2681 }
2682 do {
2683 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002684 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002685 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2686 if (c && c != ':')
2687 flags |= CD_PRINT;
2688 docd:
2689 if (!docd(p, flags))
2690 goto out;
2691 break;
2692 }
2693 } while (path);
2694 ash_msg_and_raise_error("can't cd to %s", dest);
2695 /* NOTREACHED */
2696 out:
2697 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002698 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002699 return 0;
2700}
2701
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002702static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002703pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002704{
2705 int flags;
2706 const char *dir = curdir;
2707
2708 flags = cdopt();
2709 if (flags) {
2710 if (physdir == nullstr)
2711 setpwd(dir, 0);
2712 dir = physdir;
2713 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002714 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002715 return 0;
2716}
2717
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002718
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002719/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002720
Denis Vlasenko834dee72008-10-07 09:18:30 +00002721
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002722#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002723
Eric Andersenc470f442003-07-28 09:56:35 +00002724/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002725#define CWORD 0 /* character is nothing special */
2726#define CNL 1 /* newline character */
2727#define CBACK 2 /* a backslash character */
2728#define CSQUOTE 3 /* single quote */
2729#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002730#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002731#define CBQUOTE 6 /* backwards single quote */
2732#define CVAR 7 /* a dollar sign */
2733#define CENDVAR 8 /* a '}' character */
2734#define CLP 9 /* a left paren in arithmetic */
2735#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002736#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002737#define CCTL 12 /* like CWORD, except it must be escaped */
2738#define CSPCL 13 /* these terminate a word */
2739#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002740
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002741#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002742#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002743# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002744#endif
2745
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002746#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002747
Mike Frysinger98c52642009-04-02 10:02:37 +00002748#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002749# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002750#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002751# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002752#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002753static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002754#if ENABLE_ASH_ALIAS
2755 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2756#endif
2757 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2758 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2759 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2760 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2761 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2762 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2763 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2764 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2765 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2766 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2767 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002768#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002769 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2770 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2771 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2772#endif
2773#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002774};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002775/* Constants below must match table above */
2776enum {
2777#if ENABLE_ASH_ALIAS
2778 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2779#endif
2780 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2781 CNL_CNL_CNL_CNL , /* 2 */
2782 CWORD_CCTL_CCTL_CWORD , /* 3 */
2783 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2784 CVAR_CVAR_CWORD_CVAR , /* 5 */
2785 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2786 CSPCL_CWORD_CWORD_CLP , /* 7 */
2787 CSPCL_CWORD_CWORD_CRP , /* 8 */
2788 CBACK_CBACK_CCTL_CBACK , /* 9 */
2789 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2790 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2791 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2792 CWORD_CWORD_CWORD_CWORD , /* 13 */
2793 CCTL_CCTL_CCTL_CCTL , /* 14 */
2794};
Eric Andersen2870d962001-07-02 17:27:21 +00002795
Denys Vlasenkocd716832009-11-28 22:14:02 +01002796/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2797 * caller must ensure proper cast on it if c is *char_ptr!
2798 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002799/* Values for syntax param */
2800#define BASESYNTAX 0 /* not in quotes */
2801#define DQSYNTAX 1 /* in double quotes */
2802#define SQSYNTAX 2 /* in single quotes */
2803#define ARISYNTAX 3 /* in arithmetic */
2804#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002805
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002806#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002807
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002808static int
2809SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002810{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002811 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2812 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2813 /*
2814 * This causes '/' to be prepended with CTLESC in dquoted string,
2815 * making "./file"* treated incorrectly because we feed
2816 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2817 * The "homegrown" glob implementation is okay with that,
2818 * but glibc one isn't. With '/' always treated as CWORD,
2819 * both work fine.
2820 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002821# if ENABLE_ASH_ALIAS
2822 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002823 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002824 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002825 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2826 11, 3 /* "}~" */
2827 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002828# else
2829 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002830 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002831 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002832 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2833 10, 2 /* "}~" */
2834 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002835# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002836 const char *s;
2837 int indx;
2838
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002839 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002840 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002841# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002842 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002843 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002844 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002845# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002846 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002847 /* Cast is purely for paranoia here,
2848 * just in case someone passed signed char to us */
2849 if ((unsigned char)c >= CTL_FIRST
2850 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002851 ) {
2852 return CCTL;
2853 }
2854 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002855 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002856 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002857 indx = syntax_index_table[s - spec_symbls];
2858 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002859 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002860}
2861
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002862#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002863
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002864static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002865 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002866 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2876 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2877 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2899 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2900 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2901 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2902 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2903 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2904 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2905 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2906 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2907 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2908 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2909 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2911 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2912 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002913/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2914 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002915 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2926 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2927 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2928 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2929 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2930 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2931 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2959 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2960 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2961 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2964 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2992 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2993 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2994 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2995 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2997 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2998 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2999 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3000 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3001 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3002 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3003 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3004 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003123 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003124# if ENABLE_ASH_ALIAS
3125 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3126# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003127};
3128
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003129# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003130
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003131#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003132
Eric Andersen2870d962001-07-02 17:27:21 +00003133
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003134/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003135
Denis Vlasenko131ae172007-02-18 13:00:19 +00003136#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003137
3138#define ALIASINUSE 1
3139#define ALIASDEAD 2
3140
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003141struct alias {
3142 struct alias *next;
3143 char *name;
3144 char *val;
3145 int flag;
3146};
3147
Denis Vlasenko01631112007-12-16 17:20:38 +00003148
3149static struct alias **atab; // [ATABSIZE];
3150#define INIT_G_alias() do { \
3151 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3152} while (0)
3153
Eric Andersen2870d962001-07-02 17:27:21 +00003154
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003155static struct alias **
3156__lookupalias(const char *name) {
3157 unsigned int hashval;
3158 struct alias **app;
3159 const char *p;
3160 unsigned int ch;
3161
3162 p = name;
3163
3164 ch = (unsigned char)*p;
3165 hashval = ch << 4;
3166 while (ch) {
3167 hashval += ch;
3168 ch = (unsigned char)*++p;
3169 }
3170 app = &atab[hashval % ATABSIZE];
3171
3172 for (; *app; app = &(*app)->next) {
3173 if (strcmp(name, (*app)->name) == 0) {
3174 break;
3175 }
3176 }
3177
3178 return app;
3179}
3180
3181static struct alias *
3182lookupalias(const char *name, int check)
3183{
3184 struct alias *ap = *__lookupalias(name);
3185
3186 if (check && ap && (ap->flag & ALIASINUSE))
3187 return NULL;
3188 return ap;
3189}
3190
3191static struct alias *
3192freealias(struct alias *ap)
3193{
3194 struct alias *next;
3195
3196 if (ap->flag & ALIASINUSE) {
3197 ap->flag |= ALIASDEAD;
3198 return ap;
3199 }
3200
3201 next = ap->next;
3202 free(ap->name);
3203 free(ap->val);
3204 free(ap);
3205 return next;
3206}
Eric Andersencb57d552001-06-28 07:25:16 +00003207
Eric Andersenc470f442003-07-28 09:56:35 +00003208static void
3209setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003210{
3211 struct alias *ap, **app;
3212
3213 app = __lookupalias(name);
3214 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003215 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003216 if (ap) {
3217 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003218 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003219 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003220 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003221 ap->flag &= ~ALIASDEAD;
3222 } else {
3223 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003224 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003225 ap->name = ckstrdup(name);
3226 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003227 /*ap->flag = 0; - ckzalloc did it */
3228 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003229 *app = ap;
3230 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003231 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003232}
3233
Eric Andersenc470f442003-07-28 09:56:35 +00003234static int
3235unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003236{
Eric Andersencb57d552001-06-28 07:25:16 +00003237 struct alias **app;
3238
3239 app = __lookupalias(name);
3240
3241 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003242 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003243 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003244 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003245 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003246 }
3247
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003248 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003249}
3250
Eric Andersenc470f442003-07-28 09:56:35 +00003251static void
3252rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003253{
Eric Andersencb57d552001-06-28 07:25:16 +00003254 struct alias *ap, **app;
3255 int i;
3256
Denis Vlasenkob012b102007-02-19 22:43:01 +00003257 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003258 for (i = 0; i < ATABSIZE; i++) {
3259 app = &atab[i];
3260 for (ap = *app; ap; ap = *app) {
3261 *app = freealias(*app);
3262 if (ap == *app) {
3263 app = &ap->next;
3264 }
3265 }
3266 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003267 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003268}
3269
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003270static void
3271printalias(const struct alias *ap)
3272{
3273 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3274}
3275
Eric Andersencb57d552001-06-28 07:25:16 +00003276/*
3277 * TODO - sort output
3278 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003279static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003280aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003281{
3282 char *n, *v;
3283 int ret = 0;
3284 struct alias *ap;
3285
Denis Vlasenko68404f12008-03-17 09:00:54 +00003286 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003287 int i;
3288
Denis Vlasenko68404f12008-03-17 09:00:54 +00003289 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003290 for (ap = atab[i]; ap; ap = ap->next) {
3291 printalias(ap);
3292 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003293 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003294 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003295 }
3296 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003297 v = strchr(n+1, '=');
3298 if (v == NULL) { /* n+1: funny ksh stuff */
3299 ap = *__lookupalias(n);
3300 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003301 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003302 ret = 1;
3303 } else
3304 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003305 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003306 *v++ = '\0';
3307 setalias(n, v);
3308 }
3309 }
3310
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003311 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003312}
3313
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003314static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003315unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003316{
3317 int i;
3318
3319 while ((i = nextopt("a")) != '\0') {
3320 if (i == 'a') {
3321 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003322 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003323 }
3324 }
3325 for (i = 0; *argptr; argptr++) {
3326 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003327 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003328 i = 1;
3329 }
3330 }
3331
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003332 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003333}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003334
Denis Vlasenko131ae172007-02-18 13:00:19 +00003335#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003336
Eric Andersenc470f442003-07-28 09:56:35 +00003337
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003338/* ============ jobs.c */
3339
3340/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003341#define FORK_FG 0
3342#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003343#define FORK_NOJOB 2
3344
3345/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003346#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3347#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3348#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003349#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003350
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003351/*
3352 * A job structure contains information about a job. A job is either a
3353 * single process or a set of processes contained in a pipeline. In the
3354 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3355 * array of pids.
3356 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003357struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003358 pid_t ps_pid; /* process id */
3359 int ps_status; /* last process status from wait() */
3360 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003361};
3362
3363struct job {
3364 struct procstat ps0; /* status of process */
3365 struct procstat *ps; /* status or processes when more than one */
3366#if JOBS
3367 int stopstatus; /* status of a stopped job */
3368#endif
3369 uint32_t
3370 nprocs: 16, /* number of processes */
3371 state: 8,
3372#define JOBRUNNING 0 /* at least one proc running */
3373#define JOBSTOPPED 1 /* all procs are stopped */
3374#define JOBDONE 2 /* all procs are completed */
3375#if JOBS
3376 sigint: 1, /* job was killed by SIGINT */
3377 jobctl: 1, /* job running under job control */
3378#endif
3379 waited: 1, /* true if this entry has been waited for */
3380 used: 1, /* true if this entry is in used */
3381 changed: 1; /* true if status has changed */
3382 struct job *prev_job; /* previous job */
3383};
3384
Denis Vlasenko68404f12008-03-17 09:00:54 +00003385static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003386static int forkshell(struct job *, union node *, int);
3387static int waitforjob(struct job *);
3388
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003389#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003390enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003391#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003392#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003393static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003394static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003395#endif
3396
3397/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003398 * Ignore a signal.
3399 */
3400static void
3401ignoresig(int signo)
3402{
3403 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3404 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3405 /* No, need to do it */
3406 signal(signo, SIG_IGN);
3407 }
3408 sigmode[signo - 1] = S_HARD_IGN;
3409}
3410
3411/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003412 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003413 */
3414static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003415signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003416{
3417 gotsig[signo - 1] = 1;
3418
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003419 if (signo == SIGINT && !trap[SIGINT]) {
3420 if (!suppress_int) {
3421 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003422 raise_interrupt(); /* does not return */
3423 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003424 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003425 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003426 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003427 }
3428}
3429
3430/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003431 * Set the signal handler for the specified signal. The routine figures
3432 * out what it should be set to.
3433 */
3434static void
3435setsignal(int signo)
3436{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003437 char *t;
3438 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003439 struct sigaction act;
3440
3441 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003442 new_act = S_DFL;
3443 if (t != NULL) { /* trap for this sig is set */
3444 new_act = S_CATCH;
3445 if (t[0] == '\0') /* trap is "": ignore this sig */
3446 new_act = S_IGN;
3447 }
3448
3449 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003450 switch (signo) {
3451 case SIGINT:
3452 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003453 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003454 break;
3455 case SIGQUIT:
3456#if DEBUG
3457 if (debug)
3458 break;
3459#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003460 /* man bash:
3461 * "In all cases, bash ignores SIGQUIT. Non-builtin
3462 * commands run by bash have signal handlers
3463 * set to the values inherited by the shell
3464 * from its parent". */
3465 new_act = S_IGN;
3466 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003467 case SIGTERM:
3468 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003469 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003470 break;
3471#if JOBS
3472 case SIGTSTP:
3473 case SIGTTOU:
3474 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003475 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003476 break;
3477#endif
3478 }
3479 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003480//TODO: if !rootshell, we reset SIGQUIT to DFL,
3481//whereas we have to restore it to what shell got on entry
3482//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003483
3484 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003485 cur_act = *t;
3486 if (cur_act == 0) {
3487 /* current setting is not yet known */
3488 if (sigaction(signo, NULL, &act)) {
3489 /* pretend it worked; maybe we should give a warning,
3490 * but other shells don't. We don't alter sigmode,
3491 * so we retry every time.
3492 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003493 return;
3494 }
3495 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003496 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003497 if (mflag
3498 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3499 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003500 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003501 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003502 }
3503 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003504 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003505 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003506
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003507 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003508 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003509 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003510 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003511 break;
3512 case S_IGN:
3513 act.sa_handler = SIG_IGN;
3514 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003515 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003516
3517 /* flags and mask matter only if !DFL and !IGN, but we do it
3518 * for all cases for more deterministic behavior:
3519 */
3520 act.sa_flags = 0;
3521 sigfillset(&act.sa_mask);
3522
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003523 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003524
3525 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003526}
3527
3528/* mode flags for set_curjob */
3529#define CUR_DELETE 2
3530#define CUR_RUNNING 1
3531#define CUR_STOPPED 0
3532
3533/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003534#define DOWAIT_NONBLOCK WNOHANG
3535#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003536
3537#if JOBS
3538/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003539static int initialpgrp; //references:2
3540static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003541#endif
3542/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003543static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003544/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003545static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003546/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003547static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003548/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003549static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003550
3551static void
3552set_curjob(struct job *jp, unsigned mode)
3553{
3554 struct job *jp1;
3555 struct job **jpp, **curp;
3556
3557 /* first remove from list */
3558 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003559 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003560 jp1 = *jpp;
3561 if (jp1 == jp)
3562 break;
3563 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003564 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003565 *jpp = jp1->prev_job;
3566
3567 /* Then re-insert in correct position */
3568 jpp = curp;
3569 switch (mode) {
3570 default:
3571#if DEBUG
3572 abort();
3573#endif
3574 case CUR_DELETE:
3575 /* job being deleted */
3576 break;
3577 case CUR_RUNNING:
3578 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003579 * put after all stopped jobs.
3580 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003581 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003582 jp1 = *jpp;
3583#if JOBS
3584 if (!jp1 || jp1->state != JOBSTOPPED)
3585#endif
3586 break;
3587 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003588 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003589 /* FALLTHROUGH */
3590#if JOBS
3591 case CUR_STOPPED:
3592#endif
3593 /* newly stopped job - becomes curjob */
3594 jp->prev_job = *jpp;
3595 *jpp = jp;
3596 break;
3597 }
3598}
3599
3600#if JOBS || DEBUG
3601static int
3602jobno(const struct job *jp)
3603{
3604 return jp - jobtab + 1;
3605}
3606#endif
3607
3608/*
3609 * Convert a job name to a job structure.
3610 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003611#if !JOBS
3612#define getjob(name, getctl) getjob(name)
3613#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003614static struct job *
3615getjob(const char *name, int getctl)
3616{
3617 struct job *jp;
3618 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003619 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003620 unsigned num;
3621 int c;
3622 const char *p;
3623 char *(*match)(const char *, const char *);
3624
3625 jp = curjob;
3626 p = name;
3627 if (!p)
3628 goto currentjob;
3629
3630 if (*p != '%')
3631 goto err;
3632
3633 c = *++p;
3634 if (!c)
3635 goto currentjob;
3636
3637 if (!p[1]) {
3638 if (c == '+' || c == '%') {
3639 currentjob:
3640 err_msg = "No current job";
3641 goto check;
3642 }
3643 if (c == '-') {
3644 if (jp)
3645 jp = jp->prev_job;
3646 err_msg = "No previous job";
3647 check:
3648 if (!jp)
3649 goto err;
3650 goto gotit;
3651 }
3652 }
3653
3654 if (is_number(p)) {
3655 num = atoi(p);
Denys Vlasenko46a45ce2016-09-29 01:10:08 +02003656 if (num > 0 && num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003657 jp = jobtab + num - 1;
3658 if (jp->used)
3659 goto gotit;
3660 goto err;
3661 }
3662 }
3663
3664 match = prefix;
3665 if (*p == '?') {
3666 match = strstr;
3667 p++;
3668 }
3669
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003670 found = NULL;
3671 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003672 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003673 if (found)
3674 goto err;
3675 found = jp;
3676 err_msg = "%s: ambiguous";
3677 }
3678 jp = jp->prev_job;
3679 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003680 if (!found)
3681 goto err;
3682 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003683
3684 gotit:
3685#if JOBS
3686 err_msg = "job %s not created under job control";
3687 if (getctl && jp->jobctl == 0)
3688 goto err;
3689#endif
3690 return jp;
3691 err:
3692 ash_msg_and_raise_error(err_msg, name);
3693}
3694
3695/*
3696 * Mark a job structure as unused.
3697 */
3698static void
3699freejob(struct job *jp)
3700{
3701 struct procstat *ps;
3702 int i;
3703
3704 INT_OFF;
3705 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003706 if (ps->ps_cmd != nullstr)
3707 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003708 }
3709 if (jp->ps != &jp->ps0)
3710 free(jp->ps);
3711 jp->used = 0;
3712 set_curjob(jp, CUR_DELETE);
3713 INT_ON;
3714}
3715
3716#if JOBS
3717static void
3718xtcsetpgrp(int fd, pid_t pgrp)
3719{
3720 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003721 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003722}
3723
3724/*
3725 * Turn job control on and off.
3726 *
3727 * Note: This code assumes that the third arg to ioctl is a character
3728 * pointer, which is true on Berkeley systems but not System V. Since
3729 * System V doesn't have job control yet, this isn't a problem now.
3730 *
3731 * Called with interrupts off.
3732 */
3733static void
3734setjobctl(int on)
3735{
3736 int fd;
3737 int pgrp;
3738
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003739 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003740 return;
3741 if (on) {
3742 int ofd;
3743 ofd = fd = open(_PATH_TTY, O_RDWR);
3744 if (fd < 0) {
3745 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3746 * That sometimes helps to acquire controlling tty.
3747 * Obviously, a workaround for bugs when someone
3748 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003749 fd = 2;
3750 while (!isatty(fd))
3751 if (--fd < 0)
3752 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003753 }
3754 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003755 if (ofd >= 0)
3756 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003757 if (fd < 0)
3758 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003759 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003760 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003761 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003762 pgrp = tcgetpgrp(fd);
3763 if (pgrp < 0) {
3764 out:
3765 ash_msg("can't access tty; job control turned off");
3766 mflag = on = 0;
3767 goto close;
3768 }
3769 if (pgrp == getpgrp())
3770 break;
3771 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003772 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003773 initialpgrp = pgrp;
3774
3775 setsignal(SIGTSTP);
3776 setsignal(SIGTTOU);
3777 setsignal(SIGTTIN);
3778 pgrp = rootpid;
3779 setpgid(0, pgrp);
3780 xtcsetpgrp(fd, pgrp);
3781 } else {
3782 /* turning job control off */
3783 fd = ttyfd;
3784 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003785 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003786 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003787 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003788 setpgid(0, pgrp);
3789 setsignal(SIGTSTP);
3790 setsignal(SIGTTOU);
3791 setsignal(SIGTTIN);
3792 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003793 if (fd >= 0)
3794 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003795 fd = -1;
3796 }
3797 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003798 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003799}
3800
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003801static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003802killcmd(int argc, char **argv)
3803{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003804 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003805 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003806 do {
3807 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003808 /*
3809 * "kill %N" - job kill
3810 * Converting to pgrp / pid kill
3811 */
3812 struct job *jp;
3813 char *dst;
3814 int j, n;
3815
3816 jp = getjob(argv[i], 0);
3817 /*
3818 * In jobs started under job control, we signal
3819 * entire process group by kill -PGRP_ID.
3820 * This happens, f.e., in interactive shell.
3821 *
3822 * Otherwise, we signal each child via
3823 * kill PID1 PID2 PID3.
3824 * Testcases:
3825 * sh -c 'sleep 1|sleep 1 & kill %1'
3826 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3827 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3828 */
3829 n = jp->nprocs; /* can't be 0 (I hope) */
3830 if (jp->jobctl)
3831 n = 1;
3832 dst = alloca(n * sizeof(int)*4);
3833 argv[i] = dst;
3834 for (j = 0; j < n; j++) {
3835 struct procstat *ps = &jp->ps[j];
3836 /* Skip non-running and not-stopped members
3837 * (i.e. dead members) of the job
3838 */
3839 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3840 continue;
3841 /*
3842 * kill_main has matching code to expect
3843 * leading space. Needed to not confuse
3844 * negative pids with "kill -SIGNAL_NO" syntax
3845 */
3846 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3847 }
3848 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003849 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003850 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003851 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003852 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003853}
3854
3855static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003856showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003857{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003858 struct procstat *ps;
3859 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003860
Denys Vlasenko285ad152009-12-04 23:02:27 +01003861 psend = jp->ps + jp->nprocs;
3862 for (ps = jp->ps + 1; ps < psend; ps++)
3863 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003864 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003865 flush_stdout_stderr();
3866}
3867
3868
3869static int
3870restartjob(struct job *jp, int mode)
3871{
3872 struct procstat *ps;
3873 int i;
3874 int status;
3875 pid_t pgid;
3876
3877 INT_OFF;
3878 if (jp->state == JOBDONE)
3879 goto out;
3880 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003881 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003882 if (mode == FORK_FG)
3883 xtcsetpgrp(ttyfd, pgid);
3884 killpg(pgid, SIGCONT);
3885 ps = jp->ps;
3886 i = jp->nprocs;
3887 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003888 if (WIFSTOPPED(ps->ps_status)) {
3889 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003890 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003891 ps++;
3892 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003893 out:
3894 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3895 INT_ON;
3896 return status;
3897}
3898
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003899static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003900fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003901{
3902 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003903 int mode;
3904 int retval;
3905
3906 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3907 nextopt(nullstr);
3908 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003909 do {
3910 jp = getjob(*argv, 1);
3911 if (mode == FORK_BG) {
3912 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003913 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003914 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003915 out1str(jp->ps[0].ps_cmd);
3916 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003917 retval = restartjob(jp, mode);
3918 } while (*argv && *++argv);
3919 return retval;
3920}
3921#endif
3922
3923static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003924sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003925{
3926 int col;
3927 int st;
3928
3929 col = 0;
3930 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003931 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003932 st = WSTOPSIG(status);
3933 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003934 st = WTERMSIG(status);
3935 if (sigonly) {
3936 if (st == SIGINT || st == SIGPIPE)
3937 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003938 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003939 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003940 }
3941 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003942//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003943 col = fmtstr(s, 32, strsignal(st));
3944 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003945 strcpy(s + col, " (core dumped)");
3946 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003947 }
3948 } else if (!sigonly) {
3949 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003950 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003951 }
3952 out:
3953 return col;
3954}
3955
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003956static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003957dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003958{
3959 int pid;
3960 int status;
3961 struct job *jp;
3962 struct job *thisjob;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003963
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003964 TRACE(("dowait(0x%x) called\n", wait_flags));
3965
3966 /* Do a wait system call. If job control is compiled in, we accept
3967 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3968 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003969 if (doing_jobctl)
3970 wait_flags |= WUNTRACED;
3971 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003972 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3973 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003974 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003975 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003976
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003977 INT_OFF;
3978 thisjob = NULL;
3979 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003980 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003981 struct procstat *ps;
3982 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003983 if (jp->state == JOBDONE)
3984 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003985 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003986 ps = jp->ps;
3987 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003988 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003989 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003990 TRACE(("Job %d: changing status of proc %d "
3991 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003992 jobno(jp), pid, ps->ps_status, status));
3993 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003994 thisjob = jp;
3995 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003996 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003997 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003998#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003999 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004000 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004001 if (WIFSTOPPED(ps->ps_status)) {
4002 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004003 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004004 }
4005#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004006 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004007 if (!thisjob)
4008 continue;
4009
4010 /* Found the job where one of its processes changed its state.
4011 * Is there at least one live and running process in this job? */
4012 if (jobstate != JOBRUNNING) {
4013 /* No. All live processes in the job are stopped
4014 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4015 */
4016 thisjob->changed = 1;
4017 if (thisjob->state != jobstate) {
4018 TRACE(("Job %d: changing state from %d to %d\n",
4019 jobno(thisjob), thisjob->state, jobstate));
4020 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004021#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004022 if (jobstate == JOBSTOPPED)
4023 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004024#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004025 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004026 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004027 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004028 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004029 /* The process wasn't found in job list */
4030 if (JOBS && !WIFSTOPPED(status))
4031 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004032 out:
4033 INT_ON;
4034
4035 if (thisjob && thisjob == job) {
4036 char s[48 + 1];
4037 int len;
4038
Denys Vlasenko9c541002015-10-07 15:44:36 +02004039 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004040 if (len) {
4041 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004042 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004043 out2str(s);
4044 }
4045 }
4046 return pid;
4047}
4048
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004049static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004050blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004051{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004052 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004053 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004054 raise_exception(EXSIG);
4055 return pid;
4056}
4057
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004058#if JOBS
4059static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004060showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004061{
4062 struct procstat *ps;
4063 struct procstat *psend;
4064 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004065 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004066 char s[16 + 16 + 48];
4067 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004068
4069 ps = jp->ps;
4070
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004071 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004072 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004073 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004074 return;
4075 }
4076
4077 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004078 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004079
4080 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004081 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004082 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004083 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004084
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004085 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004086 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004087
4088 psend = ps + jp->nprocs;
4089
4090 if (jp->state == JOBRUNNING) {
4091 strcpy(s + col, "Running");
4092 col += sizeof("Running") - 1;
4093 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004094 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004095 if (jp->state == JOBSTOPPED)
4096 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004097 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004098 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004099 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004100
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004101 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4102 * or prints several "PID | <cmdN>" lines,
4103 * depending on SHOW_PIDS bit.
4104 * We do not print status of individual processes
4105 * between PID and <cmdN>. bash does it, but not very well:
4106 * first line shows overall job status, not process status,
4107 * making it impossible to know 1st process status.
4108 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004109 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004110 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004111 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004112 s[0] = '\0';
4113 col = 33;
4114 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004115 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004116 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004117 fprintf(out, "%s%*c%s%s",
4118 s,
4119 33 - col >= 0 ? 33 - col : 0, ' ',
4120 ps == jp->ps ? "" : "| ",
4121 ps->ps_cmd
4122 );
4123 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004124 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004125
4126 jp->changed = 0;
4127
4128 if (jp->state == JOBDONE) {
4129 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4130 freejob(jp);
4131 }
4132}
4133
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004134/*
4135 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4136 * statuses have changed since the last call to showjobs.
4137 */
4138static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004139showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004140{
4141 struct job *jp;
4142
Denys Vlasenko883cea42009-07-11 15:31:59 +02004143 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004144
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004145 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004146 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004147 continue;
4148
4149 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004150 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004151 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004152 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004153 }
4154}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004155
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004156static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004157jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004158{
4159 int mode, m;
4160
4161 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004162 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004163 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004164 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004165 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004166 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004167 }
4168
4169 argv = argptr;
4170 if (*argv) {
4171 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004172 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004173 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004174 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004175 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004176 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004177
4178 return 0;
4179}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180#endif /* JOBS */
4181
Michael Abbott359da5e2009-12-04 23:03:29 +01004182/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004183static int
4184getstatus(struct job *job)
4185{
4186 int status;
4187 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004188 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004189
Michael Abbott359da5e2009-12-04 23:03:29 +01004190 /* Fetch last member's status */
4191 ps = job->ps + job->nprocs - 1;
4192 status = ps->ps_status;
4193 if (pipefail) {
4194 /* "set -o pipefail" mode: use last _nonzero_ status */
4195 while (status == 0 && --ps >= job->ps)
4196 status = ps->ps_status;
4197 }
4198
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004199 retval = WEXITSTATUS(status);
4200 if (!WIFEXITED(status)) {
4201#if JOBS
4202 retval = WSTOPSIG(status);
4203 if (!WIFSTOPPED(status))
4204#endif
4205 {
4206 /* XXX: limits number of signals */
4207 retval = WTERMSIG(status);
4208#if JOBS
4209 if (retval == SIGINT)
4210 job->sigint = 1;
4211#endif
4212 }
4213 retval += 128;
4214 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004215 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004216 jobno(job), job->nprocs, status, retval));
4217 return retval;
4218}
4219
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004220static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004221waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004222{
4223 struct job *job;
4224 int retval;
4225 struct job *jp;
4226
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004227 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004228 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004229
4230 nextopt(nullstr);
4231 retval = 0;
4232
4233 argv = argptr;
4234 if (!*argv) {
4235 /* wait for all jobs */
4236 for (;;) {
4237 jp = curjob;
4238 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004239 if (!jp) /* no running procs */
4240 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004241 if (jp->state == JOBRUNNING)
4242 break;
4243 jp->waited = 1;
4244 jp = jp->prev_job;
4245 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004246 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004247 /* man bash:
4248 * "When bash is waiting for an asynchronous command via
4249 * the wait builtin, the reception of a signal for which a trap
4250 * has been set will cause the wait builtin to return immediately
4251 * with an exit status greater than 128, immediately after which
4252 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004253 *
4254 * blocking_wait_with_raise_on_sig raises signal handlers
4255 * if it gets no pid (pid < 0). However,
4256 * if child sends us a signal *and immediately exits*,
4257 * blocking_wait_with_raise_on_sig gets pid > 0
4258 * and does not handle pending_sig. Check this case: */
4259 if (pending_sig)
4260 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004261 }
4262 }
4263
4264 retval = 127;
4265 do {
4266 if (**argv != '%') {
4267 pid_t pid = number(*argv);
4268 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004269 while (1) {
4270 if (!job)
4271 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004272 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004273 break;
4274 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004275 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004276 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004277 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004278 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004279 /* loop until process terminated or stopped */
4280 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004281 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004282 job->waited = 1;
4283 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004284 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004285 } while (*++argv);
4286
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004287 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004288 return retval;
4289}
4290
4291static struct job *
4292growjobtab(void)
4293{
4294 size_t len;
4295 ptrdiff_t offset;
4296 struct job *jp, *jq;
4297
4298 len = njobs * sizeof(*jp);
4299 jq = jobtab;
4300 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4301
4302 offset = (char *)jp - (char *)jq;
4303 if (offset) {
4304 /* Relocate pointers */
4305 size_t l = len;
4306
4307 jq = (struct job *)((char *)jq + l);
4308 while (l) {
4309 l -= sizeof(*jp);
4310 jq--;
4311#define joff(p) ((struct job *)((char *)(p) + l))
4312#define jmove(p) (p) = (void *)((char *)(p) + offset)
4313 if (joff(jp)->ps == &jq->ps0)
4314 jmove(joff(jp)->ps);
4315 if (joff(jp)->prev_job)
4316 jmove(joff(jp)->prev_job);
4317 }
4318 if (curjob)
4319 jmove(curjob);
4320#undef joff
4321#undef jmove
4322 }
4323
4324 njobs += 4;
4325 jobtab = jp;
4326 jp = (struct job *)((char *)jp + len);
4327 jq = jp + 3;
4328 do {
4329 jq->used = 0;
4330 } while (--jq >= jp);
4331 return jp;
4332}
4333
4334/*
4335 * Return a new job structure.
4336 * Called with interrupts off.
4337 */
4338static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004339makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004340{
4341 int i;
4342 struct job *jp;
4343
4344 for (i = njobs, jp = jobtab; ; jp++) {
4345 if (--i < 0) {
4346 jp = growjobtab();
4347 break;
4348 }
4349 if (jp->used == 0)
4350 break;
4351 if (jp->state != JOBDONE || !jp->waited)
4352 continue;
4353#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004354 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004355 continue;
4356#endif
4357 freejob(jp);
4358 break;
4359 }
4360 memset(jp, 0, sizeof(*jp));
4361#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004362 /* jp->jobctl is a bitfield.
4363 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004364 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004365 jp->jobctl = 1;
4366#endif
4367 jp->prev_job = curjob;
4368 curjob = jp;
4369 jp->used = 1;
4370 jp->ps = &jp->ps0;
4371 if (nprocs > 1) {
4372 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4373 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004374 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004375 jobno(jp)));
4376 return jp;
4377}
4378
4379#if JOBS
4380/*
4381 * Return a string identifying a command (to be printed by the
4382 * jobs command).
4383 */
4384static char *cmdnextc;
4385
4386static void
4387cmdputs(const char *s)
4388{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004389 static const char vstype[VSTYPE + 1][3] = {
4390 "", "}", "-", "+", "?", "=",
4391 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004392 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004393 };
4394
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004395 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004396 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004397 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004398 unsigned char c;
4399 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004400 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004401
Denys Vlasenko46a14772009-12-10 21:27:13 +01004402 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004403 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4404 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004405 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004406 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004407 switch (c) {
4408 case CTLESC:
4409 c = *p++;
4410 break;
4411 case CTLVAR:
4412 subtype = *p++;
4413 if ((subtype & VSTYPE) == VSLENGTH)
4414 str = "${#";
4415 else
4416 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004417 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004418 case CTLENDVAR:
4419 str = "\"}" + !(quoted & 1);
4420 quoted >>= 1;
4421 subtype = 0;
4422 goto dostr;
4423 case CTLBACKQ:
4424 str = "$(...)";
4425 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004426#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004427 case CTLARI:
4428 str = "$((";
4429 goto dostr;
4430 case CTLENDARI:
4431 str = "))";
4432 goto dostr;
4433#endif
4434 case CTLQUOTEMARK:
4435 quoted ^= 1;
4436 c = '"';
4437 break;
4438 case '=':
4439 if (subtype == 0)
4440 break;
4441 if ((subtype & VSTYPE) != VSNORMAL)
4442 quoted <<= 1;
4443 str = vstype[subtype & VSTYPE];
4444 if (subtype & VSNUL)
4445 c = ':';
4446 else
4447 goto checkstr;
4448 break;
4449 case '\'':
4450 case '\\':
4451 case '"':
4452 case '$':
4453 /* These can only happen inside quotes */
4454 cc[0] = c;
4455 str = cc;
4456 c = '\\';
4457 break;
4458 default:
4459 break;
4460 }
4461 USTPUTC(c, nextc);
4462 checkstr:
4463 if (!str)
4464 continue;
4465 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004466 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004467 USTPUTC(c, nextc);
4468 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004469 } /* while *p++ not NUL */
4470
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004471 if (quoted & 1) {
4472 USTPUTC('"', nextc);
4473 }
4474 *nextc = 0;
4475 cmdnextc = nextc;
4476}
4477
4478/* cmdtxt() and cmdlist() call each other */
4479static void cmdtxt(union node *n);
4480
4481static void
4482cmdlist(union node *np, int sep)
4483{
4484 for (; np; np = np->narg.next) {
4485 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004486 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004487 cmdtxt(np);
4488 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004489 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004490 }
4491}
4492
4493static void
4494cmdtxt(union node *n)
4495{
4496 union node *np;
4497 struct nodelist *lp;
4498 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004499
4500 if (!n)
4501 return;
4502 switch (n->type) {
4503 default:
4504#if DEBUG
4505 abort();
4506#endif
4507 case NPIPE:
4508 lp = n->npipe.cmdlist;
4509 for (;;) {
4510 cmdtxt(lp->n);
4511 lp = lp->next;
4512 if (!lp)
4513 break;
4514 cmdputs(" | ");
4515 }
4516 break;
4517 case NSEMI:
4518 p = "; ";
4519 goto binop;
4520 case NAND:
4521 p = " && ";
4522 goto binop;
4523 case NOR:
4524 p = " || ";
4525 binop:
4526 cmdtxt(n->nbinary.ch1);
4527 cmdputs(p);
4528 n = n->nbinary.ch2;
4529 goto donode;
4530 case NREDIR:
4531 case NBACKGND:
4532 n = n->nredir.n;
4533 goto donode;
4534 case NNOT:
4535 cmdputs("!");
4536 n = n->nnot.com;
4537 donode:
4538 cmdtxt(n);
4539 break;
4540 case NIF:
4541 cmdputs("if ");
4542 cmdtxt(n->nif.test);
4543 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004544 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004545 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004546 cmdputs("; else ");
4547 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004548 } else {
4549 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550 }
4551 p = "; fi";
4552 goto dotail;
4553 case NSUBSHELL:
4554 cmdputs("(");
4555 n = n->nredir.n;
4556 p = ")";
4557 goto dotail;
4558 case NWHILE:
4559 p = "while ";
4560 goto until;
4561 case NUNTIL:
4562 p = "until ";
4563 until:
4564 cmdputs(p);
4565 cmdtxt(n->nbinary.ch1);
4566 n = n->nbinary.ch2;
4567 p = "; done";
4568 dodo:
4569 cmdputs("; do ");
4570 dotail:
4571 cmdtxt(n);
4572 goto dotail2;
4573 case NFOR:
4574 cmdputs("for ");
4575 cmdputs(n->nfor.var);
4576 cmdputs(" in ");
4577 cmdlist(n->nfor.args, 1);
4578 n = n->nfor.body;
4579 p = "; done";
4580 goto dodo;
4581 case NDEFUN:
4582 cmdputs(n->narg.text);
4583 p = "() { ... }";
4584 goto dotail2;
4585 case NCMD:
4586 cmdlist(n->ncmd.args, 1);
4587 cmdlist(n->ncmd.redirect, 0);
4588 break;
4589 case NARG:
4590 p = n->narg.text;
4591 dotail2:
4592 cmdputs(p);
4593 break;
4594 case NHERE:
4595 case NXHERE:
4596 p = "<<...";
4597 goto dotail2;
4598 case NCASE:
4599 cmdputs("case ");
4600 cmdputs(n->ncase.expr->narg.text);
4601 cmdputs(" in ");
4602 for (np = n->ncase.cases; np; np = np->nclist.next) {
4603 cmdtxt(np->nclist.pattern);
4604 cmdputs(") ");
4605 cmdtxt(np->nclist.body);
4606 cmdputs(";; ");
4607 }
4608 p = "esac";
4609 goto dotail2;
4610 case NTO:
4611 p = ">";
4612 goto redir;
4613 case NCLOBBER:
4614 p = ">|";
4615 goto redir;
4616 case NAPPEND:
4617 p = ">>";
4618 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004619#if ENABLE_ASH_BASH_COMPAT
4620 case NTO2:
4621#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004622 case NTOFD:
4623 p = ">&";
4624 goto redir;
4625 case NFROM:
4626 p = "<";
4627 goto redir;
4628 case NFROMFD:
4629 p = "<&";
4630 goto redir;
4631 case NFROMTO:
4632 p = "<>";
4633 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004634 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004635 cmdputs(p);
4636 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004637 cmdputs(utoa(n->ndup.dupfd));
4638 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004639 }
4640 n = n->nfile.fname;
4641 goto donode;
4642 }
4643}
4644
4645static char *
4646commandtext(union node *n)
4647{
4648 char *name;
4649
4650 STARTSTACKSTR(cmdnextc);
4651 cmdtxt(n);
4652 name = stackblock();
4653 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4654 name, cmdnextc, cmdnextc));
4655 return ckstrdup(name);
4656}
4657#endif /* JOBS */
4658
4659/*
4660 * Fork off a subshell. If we are doing job control, give the subshell its
4661 * own process group. Jp is a job structure that the job is to be added to.
4662 * N is the command that will be evaluated by the child. Both jp and n may
4663 * be NULL. The mode parameter can be one of the following:
4664 * FORK_FG - Fork off a foreground process.
4665 * FORK_BG - Fork off a background process.
4666 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4667 * process group even if job control is on.
4668 *
4669 * When job control is turned off, background processes have their standard
4670 * input redirected to /dev/null (except for the second and later processes
4671 * in a pipeline).
4672 *
4673 * Called with interrupts off.
4674 */
4675/*
4676 * Clear traps on a fork.
4677 */
4678static void
4679clear_traps(void)
4680{
4681 char **tp;
4682
4683 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004684 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004685 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004686 if (trap_ptr == trap)
4687 free(*tp);
4688 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004689 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004690 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004691 setsignal(tp - trap);
4692 INT_ON;
4693 }
4694 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004695 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004696}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004697
4698/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004699static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004700
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004701/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004702static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004703forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004704{
4705 int oldlvl;
4706
4707 TRACE(("Child shell %d\n", getpid()));
4708 oldlvl = shlvl;
4709 shlvl++;
4710
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004711 /* man bash: "Non-builtin commands run by bash have signal handlers
4712 * set to the values inherited by the shell from its parent".
4713 * Do we do it correctly? */
4714
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004715 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004716
4717 if (mode == FORK_NOJOB /* is it `xxx` ? */
4718 && n && n->type == NCMD /* is it single cmd? */
4719 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004720 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004721 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4722 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4723 ) {
4724 TRACE(("Trap hack\n"));
4725 /* Awful hack for `trap` or $(trap).
4726 *
4727 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4728 * contains an example where "trap" is executed in a subshell:
4729 *
4730 * save_traps=$(trap)
4731 * ...
4732 * eval "$save_traps"
4733 *
4734 * Standard does not say that "trap" in subshell shall print
4735 * parent shell's traps. It only says that its output
4736 * must have suitable form, but then, in the above example
4737 * (which is not supposed to be normative), it implies that.
4738 *
4739 * bash (and probably other shell) does implement it
4740 * (traps are reset to defaults, but "trap" still shows them),
4741 * but as a result, "trap" logic is hopelessly messed up:
4742 *
4743 * # trap
4744 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4745 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4746 * # true | trap <--- trap is in subshell - no output (ditto)
4747 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4748 * trap -- 'echo Ho' SIGWINCH
4749 * # echo `(trap)` <--- in subshell in subshell - output
4750 * trap -- 'echo Ho' SIGWINCH
4751 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4752 * trap -- 'echo Ho' SIGWINCH
4753 *
4754 * The rules when to forget and when to not forget traps
4755 * get really complex and nonsensical.
4756 *
4757 * Our solution: ONLY bare $(trap) or `trap` is special.
4758 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004759 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004760 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004761 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004762 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004763 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004764#if JOBS
4765 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004766 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004767 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004768 pid_t pgrp;
4769
4770 if (jp->nprocs == 0)
4771 pgrp = getpid();
4772 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004773 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004774 /* this can fail because we are doing it in the parent also */
4775 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004776 if (mode == FORK_FG)
4777 xtcsetpgrp(ttyfd, pgrp);
4778 setsignal(SIGTSTP);
4779 setsignal(SIGTTOU);
4780 } else
4781#endif
4782 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004783 /* man bash: "When job control is not in effect,
4784 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004785 ignoresig(SIGINT);
4786 ignoresig(SIGQUIT);
4787 if (jp->nprocs == 0) {
4788 close(0);
4789 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004790 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004791 }
4792 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004793 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004794 if (iflag) { /* why if iflag only? */
4795 setsignal(SIGINT);
4796 setsignal(SIGTERM);
4797 }
4798 /* man bash:
4799 * "In all cases, bash ignores SIGQUIT. Non-builtin
4800 * commands run by bash have signal handlers
4801 * set to the values inherited by the shell
4802 * from its parent".
4803 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004804 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004805 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004806#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004807 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004808 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004809 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004810 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004811 /* "jobs": we do not want to clear job list for it,
4812 * instead we remove only _its_ own_ job from job list.
4813 * This makes "jobs .... | cat" more useful.
4814 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004815 freejob(curjob);
4816 return;
4817 }
4818#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004819 for (jp = curjob; jp; jp = jp->prev_job)
4820 freejob(jp);
4821 jobless = 0;
4822}
4823
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004824/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004825#if !JOBS
4826#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4827#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004828static void
4829forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4830{
4831 TRACE(("In parent shell: child = %d\n", pid));
4832 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004833 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4834 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004835 jobless++;
4836 return;
4837 }
4838#if JOBS
4839 if (mode != FORK_NOJOB && jp->jobctl) {
4840 int pgrp;
4841
4842 if (jp->nprocs == 0)
4843 pgrp = pid;
4844 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004845 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004846 /* This can fail because we are doing it in the child also */
4847 setpgid(pid, pgrp);
4848 }
4849#endif
4850 if (mode == FORK_BG) {
4851 backgndpid = pid; /* set $! */
4852 set_curjob(jp, CUR_RUNNING);
4853 }
4854 if (jp) {
4855 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004856 ps->ps_pid = pid;
4857 ps->ps_status = -1;
4858 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004859#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004860 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004861 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004862#endif
4863 }
4864}
4865
4866static int
4867forkshell(struct job *jp, union node *n, int mode)
4868{
4869 int pid;
4870
4871 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4872 pid = fork();
4873 if (pid < 0) {
4874 TRACE(("Fork failed, errno=%d", errno));
4875 if (jp)
4876 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004877 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004878 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004879 if (pid == 0) {
4880 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004881 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004882 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004883 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004884 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004885 return pid;
4886}
4887
4888/*
4889 * Wait for job to finish.
4890 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004891 * Under job control we have the problem that while a child process
4892 * is running interrupts generated by the user are sent to the child
4893 * but not to the shell. This means that an infinite loop started by
4894 * an interactive user may be hard to kill. With job control turned off,
4895 * an interactive user may place an interactive program inside a loop.
4896 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004897 * these interrupts to also abort the loop. The approach we take here
4898 * is to have the shell ignore interrupt signals while waiting for a
4899 * foreground process to terminate, and then send itself an interrupt
4900 * signal if the child process was terminated by an interrupt signal.
4901 * Unfortunately, some programs want to do a bit of cleanup and then
4902 * exit on interrupt; unless these processes terminate themselves by
4903 * sending a signal to themselves (instead of calling exit) they will
4904 * confuse this approach.
4905 *
4906 * Called with interrupts off.
4907 */
4908static int
4909waitforjob(struct job *jp)
4910{
4911 int st;
4912
4913 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004914
4915 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004916 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004917 /* In non-interactive shells, we _can_ get
4918 * a keyboard signal here and be EINTRed,
4919 * but we just loop back, waiting for command to complete.
4920 *
4921 * man bash:
4922 * "If bash is waiting for a command to complete and receives
4923 * a signal for which a trap has been set, the trap
4924 * will not be executed until the command completes."
4925 *
4926 * Reality is that even if trap is not set, bash
4927 * will not act on the signal until command completes.
4928 * Try this. sleep5intoff.c:
4929 * #include <signal.h>
4930 * #include <unistd.h>
4931 * int main() {
4932 * sigset_t set;
4933 * sigemptyset(&set);
4934 * sigaddset(&set, SIGINT);
4935 * sigaddset(&set, SIGQUIT);
4936 * sigprocmask(SIG_BLOCK, &set, NULL);
4937 * sleep(5);
4938 * return 0;
4939 * }
4940 * $ bash -c './sleep5intoff; echo hi'
4941 * ^C^C^C^C <--- pressing ^C once a second
4942 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004943 * $ bash -c './sleep5intoff; echo hi'
4944 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4945 * $ _
4946 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004947 dowait(DOWAIT_BLOCK, jp);
4948 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004949 INT_ON;
4950
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004951 st = getstatus(jp);
4952#if JOBS
4953 if (jp->jobctl) {
4954 xtcsetpgrp(ttyfd, rootpid);
4955 /*
4956 * This is truly gross.
4957 * If we're doing job control, then we did a TIOCSPGRP which
4958 * caused us (the shell) to no longer be in the controlling
4959 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4960 * intuit from the subprocess exit status whether a SIGINT
4961 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4962 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004963 if (jp->sigint) /* TODO: do the same with all signals */
4964 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004965 }
4966 if (jp->state == JOBDONE)
4967#endif
4968 freejob(jp);
4969 return st;
4970}
4971
4972/*
4973 * return 1 if there are stopped jobs, otherwise 0
4974 */
4975static int
4976stoppedjobs(void)
4977{
4978 struct job *jp;
4979 int retval;
4980
4981 retval = 0;
4982 if (job_warning)
4983 goto out;
4984 jp = curjob;
4985 if (jp && jp->state == JOBSTOPPED) {
4986 out2str("You have stopped jobs.\n");
4987 job_warning = 2;
4988 retval++;
4989 }
4990 out:
4991 return retval;
4992}
4993
4994
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004995/* ============ redir.c
4996 *
4997 * Code for dealing with input/output redirection.
4998 */
4999
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005000#undef EMPTY
5001#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005002#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005003#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005004
5005/*
5006 * Open a file in noclobber mode.
5007 * The code was copied from bash.
5008 */
5009static int
5010noclobberopen(const char *fname)
5011{
5012 int r, fd;
5013 struct stat finfo, finfo2;
5014
5015 /*
5016 * If the file exists and is a regular file, return an error
5017 * immediately.
5018 */
5019 r = stat(fname, &finfo);
5020 if (r == 0 && S_ISREG(finfo.st_mode)) {
5021 errno = EEXIST;
5022 return -1;
5023 }
5024
5025 /*
5026 * If the file was not present (r != 0), make sure we open it
5027 * exclusively so that if it is created before we open it, our open
5028 * will fail. Make sure that we do not truncate an existing file.
5029 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5030 * file was not a regular file, we leave O_EXCL off.
5031 */
5032 if (r != 0)
5033 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5034 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5035
5036 /* If the open failed, return the file descriptor right away. */
5037 if (fd < 0)
5038 return fd;
5039
5040 /*
5041 * OK, the open succeeded, but the file may have been changed from a
5042 * non-regular file to a regular file between the stat and the open.
5043 * We are assuming that the O_EXCL open handles the case where FILENAME
5044 * did not exist and is symlinked to an existing file between the stat
5045 * and open.
5046 */
5047
5048 /*
5049 * If we can open it and fstat the file descriptor, and neither check
5050 * revealed that it was a regular file, and the file has not been
5051 * replaced, return the file descriptor.
5052 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005053 if (fstat(fd, &finfo2) == 0
5054 && !S_ISREG(finfo2.st_mode)
5055 && finfo.st_dev == finfo2.st_dev
5056 && finfo.st_ino == finfo2.st_ino
5057 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005058 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005059 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005060
5061 /* The file has been replaced. badness. */
5062 close(fd);
5063 errno = EEXIST;
5064 return -1;
5065}
5066
5067/*
5068 * Handle here documents. Normally we fork off a process to write the
5069 * data to a pipe. If the document is short, we can stuff the data in
5070 * the pipe without forking.
5071 */
5072/* openhere needs this forward reference */
5073static void expandhere(union node *arg, int fd);
5074static int
5075openhere(union node *redir)
5076{
5077 int pip[2];
5078 size_t len = 0;
5079
5080 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005081 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005082 if (redir->type == NHERE) {
5083 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005084 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005085 full_write(pip[1], redir->nhere.doc->narg.text, len);
5086 goto out;
5087 }
5088 }
5089 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005090 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005091 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005092 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5093 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5094 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5095 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005096 signal(SIGPIPE, SIG_DFL);
5097 if (redir->type == NHERE)
5098 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005099 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005100 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005101 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005102 }
5103 out:
5104 close(pip[1]);
5105 return pip[0];
5106}
5107
5108static int
5109openredirect(union node *redir)
5110{
5111 char *fname;
5112 int f;
5113
5114 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005115/* Can't happen, our single caller does this itself */
5116// case NTOFD:
5117// case NFROMFD:
5118// return -1;
5119 case NHERE:
5120 case NXHERE:
5121 return openhere(redir);
5122 }
5123
5124 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5125 * allocated space. Do it only when we know it is safe.
5126 */
5127 fname = redir->nfile.expfname;
5128
5129 switch (redir->nfile.type) {
5130 default:
5131#if DEBUG
5132 abort();
5133#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005134 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005135 f = open(fname, O_RDONLY);
5136 if (f < 0)
5137 goto eopen;
5138 break;
5139 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005140 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005141 if (f < 0)
5142 goto ecreate;
5143 break;
5144 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005145#if ENABLE_ASH_BASH_COMPAT
5146 case NTO2:
5147#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005148 /* Take care of noclobber mode. */
5149 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005150 f = noclobberopen(fname);
5151 if (f < 0)
5152 goto ecreate;
5153 break;
5154 }
5155 /* FALLTHROUGH */
5156 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005157 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5158 if (f < 0)
5159 goto ecreate;
5160 break;
5161 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005162 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5163 if (f < 0)
5164 goto ecreate;
5165 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005166 }
5167
5168 return f;
5169 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005170 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005171 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005172 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005173}
5174
5175/*
5176 * Copy a file descriptor to be >= to. Returns -1
5177 * if the source file descriptor is closed, EMPTY if there are no unused
5178 * file descriptors left.
5179 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005180/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5181 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005182enum {
5183 COPYFD_EXACT = (int)~(INT_MAX),
5184 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5185};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005186static int
5187copyfd(int from, int to)
5188{
5189 int newfd;
5190
Denis Vlasenko5a867312008-07-24 19:46:38 +00005191 if (to & COPYFD_EXACT) {
5192 to &= ~COPYFD_EXACT;
5193 /*if (from != to)*/
5194 newfd = dup2(from, to);
5195 } else {
5196 newfd = fcntl(from, F_DUPFD, to);
5197 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005198 if (newfd < 0) {
5199 if (errno == EMFILE)
5200 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005201 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005202 ash_msg_and_raise_error("%d: %m", from);
5203 }
5204 return newfd;
5205}
5206
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005207/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005208struct two_fd_t {
5209 int orig, copy;
5210};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005211struct redirtab {
5212 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005213 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005214 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005215 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005216};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005217#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005218
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005219static int need_to_remember(struct redirtab *rp, int fd)
5220{
5221 int i;
5222
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005223 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005224 return 0;
5225
5226 for (i = 0; i < rp->pair_count; i++) {
5227 if (rp->two_fd[i].orig == fd) {
5228 /* already remembered */
5229 return 0;
5230 }
5231 }
5232 return 1;
5233}
5234
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005235/* "hidden" fd is a fd used to read scripts, or a copy of such */
5236static int is_hidden_fd(struct redirtab *rp, int fd)
5237{
5238 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005239 struct parsefile *pf;
5240
5241 if (fd == -1)
5242 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005243 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005244 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005245 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005246 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005247 * $ ash # running ash interactively
5248 * $ . ./script.sh
5249 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005250 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005251 * it's still ok to use it: "read" builtin uses it,
5252 * why should we cripple "exec" builtin?
5253 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005254 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005255 return 1;
5256 }
5257 pf = pf->prev;
5258 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005259
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005260 if (!rp)
5261 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005262 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005263 fd |= COPYFD_RESTORE;
5264 for (i = 0; i < rp->pair_count; i++) {
5265 if (rp->two_fd[i].copy == fd) {
5266 return 1;
5267 }
5268 }
5269 return 0;
5270}
5271
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005272/*
5273 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5274 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005275 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005276 */
5277/* flags passed to redirect */
5278#define REDIR_PUSH 01 /* save previous values of file descriptors */
5279#define REDIR_SAVEFD2 03 /* set preverrout */
5280static void
5281redirect(union node *redir, int flags)
5282{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005283 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005284 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005285 int i;
5286 int fd;
5287 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005288 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005289
Denis Vlasenko01631112007-12-16 17:20:38 +00005290 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005291 if (!redir) {
5292 return;
5293 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005294
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005295 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005296 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005297 INT_OFF;
5298 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005299 union node *tmp = redir;
5300 do {
5301 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005302#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005303 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005304 sv_pos++;
5305#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005306 tmp = tmp->nfile.next;
5307 } while (tmp);
5308 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005309 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005310 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005311 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005312 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005313 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005314 while (sv_pos > 0) {
5315 sv_pos--;
5316 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5317 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005318 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005319
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005320 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005321 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005322 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005323 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005324 right_fd = redir->ndup.dupfd;
5325 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005326 /* redirect from/to same file descriptor? */
5327 if (right_fd == fd)
5328 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005329 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005330 if (is_hidden_fd(sv, right_fd)) {
5331 errno = EBADF; /* as if it is closed */
5332 ash_msg_and_raise_error("%d: %m", right_fd);
5333 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005334 newfd = -1;
5335 } else {
5336 newfd = openredirect(redir); /* always >= 0 */
5337 if (fd == newfd) {
5338 /* Descriptor wasn't open before redirect.
5339 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005340 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005341 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005342 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005343 continue;
5344 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005345 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005346#if ENABLE_ASH_BASH_COMPAT
5347 redirect_more:
5348#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005349 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005350 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005351 /* Careful to not accidentally "save"
5352 * to the same fd as right side fd in N>&M */
5353 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5354 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005355/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5356 * are closed in popredir() in the child, preventing them from leaking
5357 * into child. (popredir() also cleans up the mess in case of failures)
5358 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005359 if (i == -1) {
5360 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005361 if (i != EBADF) {
5362 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005363 if (newfd >= 0)
5364 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005365 errno = i;
5366 ash_msg_and_raise_error("%d: %m", fd);
5367 /* NOTREACHED */
5368 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005369 /* EBADF: it is not open - good, remember to close it */
5370 remember_to_close:
5371 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005372 } else { /* fd is open, save its copy */
5373 /* "exec fd>&-" should not close fds
5374 * which point to script file(s).
5375 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005376 if (is_hidden_fd(sv, fd))
5377 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005378 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005379 if (fd == 2)
5380 copied_fd2 = i;
5381 sv->two_fd[sv_pos].orig = fd;
5382 sv->two_fd[sv_pos].copy = i;
5383 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005384 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005385 if (newfd < 0) {
5386 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005387 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005388 /* Don't want to trigger debugging */
5389 if (fd != -1)
5390 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005391 } else {
5392 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005393 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005394 } else if (fd != newfd) { /* move newfd to fd */
5395 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005396#if ENABLE_ASH_BASH_COMPAT
5397 if (!(redir->nfile.type == NTO2 && fd == 2))
5398#endif
5399 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005400 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005401#if ENABLE_ASH_BASH_COMPAT
5402 if (redir->nfile.type == NTO2 && fd == 1) {
5403 /* We already redirected it to fd 1, now copy it to 2 */
5404 newfd = 1;
5405 fd = 2;
5406 goto redirect_more;
5407 }
5408#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005409 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005410
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005411 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005412 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5413 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005414}
5415
5416/*
5417 * Undo the effects of the last redirection.
5418 */
5419static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005420popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005421{
5422 struct redirtab *rp;
5423 int i;
5424
Ron Yorston95650a82015-10-30 19:07:37 +00005425 if (--g_nullredirs >= 0 || redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005426 return;
5427 INT_OFF;
5428 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005429 for (i = 0; i < rp->pair_count; i++) {
5430 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005431 int copy = rp->two_fd[i].copy;
5432 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005433 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005434 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005435 continue;
5436 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005437 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005438 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005439 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005440 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005441 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005442 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005443 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005444 }
5445 }
5446 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005447 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005448 free(rp);
5449 INT_ON;
5450}
5451
5452/*
5453 * Undo all redirections. Called on error or interrupt.
5454 */
5455
5456/*
5457 * Discard all saved file descriptors.
5458 */
5459static void
5460clearredir(int drop)
5461{
5462 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005463 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005464 if (!redirlist)
5465 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005466 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005467 }
5468}
5469
5470static int
5471redirectsafe(union node *redir, int flags)
5472{
5473 int err;
5474 volatile int saveint;
5475 struct jmploc *volatile savehandler = exception_handler;
5476 struct jmploc jmploc;
5477
5478 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005479 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5480 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005481 if (!err) {
5482 exception_handler = &jmploc;
5483 redirect(redir, flags);
5484 }
5485 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005486 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005487 longjmp(exception_handler->loc, 1);
5488 RESTORE_INT(saveint);
5489 return err;
5490}
5491
5492
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005493/* ============ Routines to expand arguments to commands
5494 *
5495 * We have to deal with backquotes, shell variables, and file metacharacters.
5496 */
5497
Mike Frysinger98c52642009-04-02 10:02:37 +00005498#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005499static arith_t
5500ash_arith(const char *s)
5501{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005502 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005503 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005504
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005505 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005506 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005507 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005508
5509 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005510 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005511 if (math_state.errmsg)
5512 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005513 INT_ON;
5514
5515 return result;
5516}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005517#endif
5518
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005519/*
5520 * expandarg flags
5521 */
5522#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5523#define EXP_TILDE 0x2 /* do normal tilde expansion */
5524#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5525#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5526#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005527#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005528#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5529#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005530#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005531/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005532 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005533 */
5534#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5535#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005536#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5537#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005538#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005539
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005540/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005541#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005542/* Do not skip NUL characters. */
5543#define QUOTES_KEEPNUL EXP_TILDE
5544
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005545/*
5546 * Structure specifying which parts of the string should be searched
5547 * for IFS characters.
5548 */
5549struct ifsregion {
5550 struct ifsregion *next; /* next region in list */
5551 int begoff; /* offset of start of region */
5552 int endoff; /* offset of end of region */
5553 int nulonly; /* search for nul bytes only */
5554};
5555
5556struct arglist {
5557 struct strlist *list;
5558 struct strlist **lastp;
5559};
5560
5561/* output of current string */
5562static char *expdest;
5563/* list of back quote expressions */
5564static struct nodelist *argbackq;
5565/* first struct in list of ifs regions */
5566static struct ifsregion ifsfirst;
5567/* last struct in list */
5568static struct ifsregion *ifslastp;
5569/* holds expanded arg list */
5570static struct arglist exparg;
5571
5572/*
5573 * Our own itoa().
5574 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005575#if !ENABLE_SH_MATH_SUPPORT
5576/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5577typedef long arith_t;
5578# define ARITH_FMT "%ld"
5579#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005580static int
5581cvtnum(arith_t num)
5582{
5583 int len;
5584
Denys Vlasenko9c541002015-10-07 15:44:36 +02005585 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5586 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005587 STADJUST(len, expdest);
5588 return len;
5589}
5590
5591static size_t
5592esclen(const char *start, const char *p)
5593{
5594 size_t esc = 0;
5595
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005596 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005597 esc++;
5598 }
5599 return esc;
5600}
5601
5602/*
5603 * Remove any CTLESC characters from a string.
5604 */
5605static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005606rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005607{
Ron Yorston417622c2015-05-18 09:59:14 +02005608 static const char qchars[] ALIGN1 = {
5609 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005610
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005611 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005612 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005613 unsigned protect_against_glob;
5614 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005615 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005616
Ron Yorston417622c2015-05-18 09:59:14 +02005617 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005618 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005619 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005620
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005621 q = p;
5622 r = str;
5623 if (flag & RMESCAPE_ALLOC) {
5624 size_t len = p - str;
5625 size_t fulllen = len + strlen(p) + 1;
5626
5627 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005628 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005629 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005630 /* p and str may be invalidated by makestrspace */
5631 str = (char *)stackblock() + strloc;
5632 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005633 } else if (flag & RMESCAPE_HEAP) {
5634 r = ckmalloc(fulllen);
5635 } else {
5636 r = stalloc(fulllen);
5637 }
5638 q = r;
5639 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005640 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005641 }
5642 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005643
Ron Yorston549deab2015-05-18 09:57:51 +02005644 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005645 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005646 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005647 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005648 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005649// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005650 inquotes = ~inquotes;
5651 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005652 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005653 continue;
5654 }
Ron Yorston549deab2015-05-18 09:57:51 +02005655 if ((unsigned char)*p == CTLESC) {
5656 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005657#if DEBUG
5658 if (*p == '\0')
5659 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5660#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005661 if (protect_against_glob) {
5662 *q++ = '\\';
5663 }
5664 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005665 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005666 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005667 goto copy;
5668 }
Ron Yorston417622c2015-05-18 09:59:14 +02005669#if ENABLE_ASH_BASH_COMPAT
5670 else if (*p == '/' && slash) {
5671 /* stop handling globbing and mark location of slash */
5672 globbing = slash = 0;
5673 *p = CTLESC;
5674 }
5675#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005676 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005677 copy:
5678 *q++ = *p++;
5679 }
5680 *q = '\0';
5681 if (flag & RMESCAPE_GROW) {
5682 expdest = r;
5683 STADJUST(q - r + 1, expdest);
5684 }
5685 return r;
5686}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005687#define pmatch(a, b) !fnmatch((a), (b), 0)
5688
5689/*
5690 * Prepare a pattern for a expmeta (internal glob(3)) call.
5691 *
5692 * Returns an stalloced string.
5693 */
5694static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005695preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005696{
Ron Yorston549deab2015-05-18 09:57:51 +02005697 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005698}
5699
5700/*
5701 * Put a string on the stack.
5702 */
5703static void
5704memtodest(const char *p, size_t len, int syntax, int quotes)
5705{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005706 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005707
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005708 if (!len)
5709 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005710
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005711 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5712
5713 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005714 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005715 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005716 int n = SIT(c, syntax);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005717 if ((quotes & QUOTES_ESC)
5718 && ((n == CCTL)
5719 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5720 && n == CBACK)
5721 )
5722 ) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005723 USTPUTC(CTLESC, q);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005724 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005725 } else if (!(quotes & QUOTES_KEEPNUL))
5726 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005727 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005728 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005729
5730 expdest = q;
5731}
5732
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005733static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005734strtodest(const char *p, int syntax, int quotes)
5735{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005736 size_t len = strlen(p);
5737 memtodest(p, len, syntax, quotes);
5738 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005739}
5740
5741/*
5742 * Record the fact that we have to scan this region of the
5743 * string for IFS characters.
5744 */
5745static void
5746recordregion(int start, int end, int nulonly)
5747{
5748 struct ifsregion *ifsp;
5749
5750 if (ifslastp == NULL) {
5751 ifsp = &ifsfirst;
5752 } else {
5753 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005754 ifsp = ckzalloc(sizeof(*ifsp));
5755 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005756 ifslastp->next = ifsp;
5757 INT_ON;
5758 }
5759 ifslastp = ifsp;
5760 ifslastp->begoff = start;
5761 ifslastp->endoff = end;
5762 ifslastp->nulonly = nulonly;
5763}
5764
5765static void
5766removerecordregions(int endoff)
5767{
5768 if (ifslastp == NULL)
5769 return;
5770
5771 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005772 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005773 struct ifsregion *ifsp;
5774 INT_OFF;
5775 ifsp = ifsfirst.next->next;
5776 free(ifsfirst.next);
5777 ifsfirst.next = ifsp;
5778 INT_ON;
5779 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005780 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005781 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005782 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005783 ifslastp = &ifsfirst;
5784 ifsfirst.endoff = endoff;
5785 }
5786 return;
5787 }
5788
5789 ifslastp = &ifsfirst;
5790 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005791 ifslastp = ifslastp->next;
5792 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005793 struct ifsregion *ifsp;
5794 INT_OFF;
5795 ifsp = ifslastp->next->next;
5796 free(ifslastp->next);
5797 ifslastp->next = ifsp;
5798 INT_ON;
5799 }
5800 if (ifslastp->endoff > endoff)
5801 ifslastp->endoff = endoff;
5802}
5803
5804static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005805exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005806{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005807 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005808 char *name;
5809 struct passwd *pw;
5810 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005811 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005812
5813 name = p + 1;
5814
5815 while ((c = *++p) != '\0') {
5816 switch (c) {
5817 case CTLESC:
5818 return startp;
5819 case CTLQUOTEMARK:
5820 return startp;
5821 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005822 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005823 goto done;
5824 break;
5825 case '/':
5826 case CTLENDVAR:
5827 goto done;
5828 }
5829 }
5830 done:
5831 *p = '\0';
5832 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005833 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005834 } else {
5835 pw = getpwnam(name);
5836 if (pw == NULL)
5837 goto lose;
5838 home = pw->pw_dir;
5839 }
5840 if (!home || !*home)
5841 goto lose;
5842 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005843 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005844 return p;
5845 lose:
5846 *p = c;
5847 return startp;
5848}
5849
5850/*
5851 * Execute a command inside back quotes. If it's a builtin command, we
5852 * want to save its output in a block obtained from malloc. Otherwise
5853 * we fork off a subprocess and get the output of the command via a pipe.
5854 * Should be called with interrupts off.
5855 */
5856struct backcmd { /* result of evalbackcmd */
5857 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005858 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005859 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005860 struct job *jp; /* job structure for command */
5861};
5862
5863/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005864static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005865#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02005866static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005867
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005868static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005869evalbackcmd(union node *n, struct backcmd *result)
5870{
5871 int saveherefd;
5872
5873 result->fd = -1;
5874 result->buf = NULL;
5875 result->nleft = 0;
5876 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005877 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005878 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005879
5880 saveherefd = herefd;
5881 herefd = -1;
5882
5883 {
5884 int pip[2];
5885 struct job *jp;
5886
5887 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005888 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005889 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005890 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5891 FORCE_INT_ON;
5892 close(pip[0]);
5893 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005894 /*close(1);*/
5895 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005896 close(pip[1]);
5897 }
5898 eflag = 0;
5899 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5900 /* NOTREACHED */
5901 }
5902 close(pip[1]);
5903 result->fd = pip[0];
5904 result->jp = jp;
5905 }
5906 herefd = saveherefd;
5907 out:
5908 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5909 result->fd, result->buf, result->nleft, result->jp));
5910}
5911
5912/*
5913 * Expand stuff in backwards quotes.
5914 */
5915static void
Ron Yorston549deab2015-05-18 09:57:51 +02005916expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005917{
5918 struct backcmd in;
5919 int i;
5920 char buf[128];
5921 char *p;
5922 char *dest;
5923 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02005924 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005925 struct stackmark smark;
5926
5927 INT_OFF;
Denys Vlasenko60ca8342016-09-30 11:21:21 +02005928 startloc = expdest - (char *)stackblock();
5929 pushstackmark(&smark, startloc);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005930 evalbackcmd(cmd, &in);
5931 popstackmark(&smark);
5932
5933 p = in.buf;
5934 i = in.nleft;
5935 if (i == 0)
5936 goto read;
5937 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02005938 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005939 read:
5940 if (in.fd < 0)
5941 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01005942 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005943 TRACE(("expbackq: read returns %d\n", i));
5944 if (i <= 0)
5945 break;
5946 p = buf;
5947 }
5948
Denis Vlasenko60818682007-09-28 22:07:23 +00005949 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005950 if (in.fd >= 0) {
5951 close(in.fd);
5952 back_exitstatus = waitforjob(in.jp);
5953 }
5954 INT_ON;
5955
5956 /* Eat all trailing newlines */
5957 dest = expdest;
5958 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5959 STUNPUTC(dest);
5960 expdest = dest;
5961
Ron Yorston549deab2015-05-18 09:57:51 +02005962 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005963 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005964 TRACE(("evalbackq: size:%d:'%.*s'\n",
5965 (int)((dest - (char *)stackblock()) - startloc),
5966 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005967 stackblock() + startloc));
5968}
5969
Mike Frysinger98c52642009-04-02 10:02:37 +00005970#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005971/*
5972 * Expand arithmetic expression. Backup to start of expression,
5973 * evaluate, place result in (backed up) result, adjust string position.
5974 */
5975static void
Ron Yorston549deab2015-05-18 09:57:51 +02005976expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005977{
5978 char *p, *start;
5979 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005980 int len;
5981
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005982 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005983
5984 /*
5985 * This routine is slightly over-complicated for
5986 * efficiency. Next we scan backwards looking for the
5987 * start of arithmetic.
5988 */
5989 start = stackblock();
5990 p = expdest - 1;
5991 *p = '\0';
5992 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005993 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005994 int esc;
5995
Denys Vlasenkocd716832009-11-28 22:14:02 +01005996 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005997 p--;
5998#if DEBUG
5999 if (p < start) {
6000 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6001 }
6002#endif
6003 }
6004
6005 esc = esclen(start, p);
6006 if (!(esc % 2)) {
6007 break;
6008 }
6009
6010 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006011 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006012
6013 begoff = p - start;
6014
6015 removerecordregions(begoff);
6016
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006017 expdest = p;
6018
Ron Yorston549deab2015-05-18 09:57:51 +02006019 if (flag & QUOTES_ESC)
6020 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006021
Ron Yorston549deab2015-05-18 09:57:51 +02006022 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006023
Ron Yorston549deab2015-05-18 09:57:51 +02006024 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006025 recordregion(begoff, begoff + len, 0);
6026}
6027#endif
6028
6029/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006030static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006031
6032/*
6033 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6034 * characters to allow for further processing. Otherwise treat
6035 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006036 *
6037 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6038 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6039 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006040 */
6041static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006042argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006043{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006044 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006045 '=',
6046 ':',
6047 CTLQUOTEMARK,
6048 CTLENDVAR,
6049 CTLESC,
6050 CTLVAR,
6051 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006052#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006053 CTLENDARI,
6054#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006055 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006056 };
6057 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006058 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006059 int inquotes;
6060 size_t length;
6061 int startloc;
6062
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006063 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006064 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006065 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006066 reject++;
6067 }
6068 inquotes = 0;
6069 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006070 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006071 char *q;
6072
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006073 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006074 tilde:
6075 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006076 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006077 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006078 }
6079 start:
6080 startloc = expdest - (char *)stackblock();
6081 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006082 unsigned char c;
6083
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006084 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006085 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006086 if (c) {
6087 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006088 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006089 ) {
6090 /* c == '=' || c == ':' || c == CTLENDARI */
6091 length++;
6092 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006093 }
6094 if (length > 0) {
6095 int newloc;
6096 expdest = stack_nputstr(p, length, expdest);
6097 newloc = expdest - (char *)stackblock();
6098 if (breakall && !inquotes && newloc > startloc) {
6099 recordregion(startloc, newloc, 0);
6100 }
6101 startloc = newloc;
6102 }
6103 p += length + 1;
6104 length = 0;
6105
6106 switch (c) {
6107 case '\0':
6108 goto breakloop;
6109 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006110 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006111 p--;
6112 continue;
6113 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006114 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006115 reject++;
6116 /* fall through */
6117 case ':':
6118 /*
6119 * sort of a hack - expand tildes in variable
6120 * assignments (after the first '=' and after ':'s).
6121 */
6122 if (*--p == '~') {
6123 goto tilde;
6124 }
6125 continue;
6126 }
6127
6128 switch (c) {
6129 case CTLENDVAR: /* ??? */
6130 goto breakloop;
6131 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006132 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006133 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006134 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6135 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006136 goto start;
6137 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006138 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006139 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006140 p--;
6141 length++;
6142 startloc++;
6143 }
6144 break;
6145 case CTLESC:
6146 startloc++;
6147 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006148
6149 /*
6150 * Quoted parameter expansion pattern: remove quote
6151 * unless inside inner quotes or we have a literal
6152 * backslash.
6153 */
6154 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6155 EXP_QPAT && *p != '\\')
6156 break;
6157
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006158 goto addquote;
6159 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006160 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006161 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006162 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006163 goto start;
6164 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006165 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006166 argbackq = argbackq->next;
6167 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006168#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006169 case CTLENDARI:
6170 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006171 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172 goto start;
6173#endif
6174 }
6175 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006176 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006177}
6178
6179static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006180scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6181 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006182{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006183 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006184 char c;
6185
6186 loc = startp;
6187 loc2 = rmesc;
6188 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006189 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006190 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006191
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006192 c = *loc2;
6193 if (zero) {
6194 *loc2 = '\0';
6195 s = rmesc;
6196 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006197 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006198
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006199 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006200 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006201 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006202 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006203 loc++;
6204 loc++;
6205 loc2++;
6206 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006207 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006208}
6209
6210static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006211scanright(char *startp, char *rmesc, char *rmescend,
6212 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006213{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006214#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6215 int try2optimize = match_at_start;
6216#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006217 int esc = 0;
6218 char *loc;
6219 char *loc2;
6220
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006221 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6222 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6223 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6224 * Logic:
6225 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6226 * and on each iteration they go back two/one char until they reach the beginning.
6227 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6228 */
6229 /* TODO: document in what other circumstances we are called. */
6230
6231 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006232 int match;
6233 char c = *loc2;
6234 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006235 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006236 *loc2 = '\0';
6237 s = rmesc;
6238 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006239 match = pmatch(pattern, s);
6240 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006241 *loc2 = c;
6242 if (match)
6243 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006244#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6245 if (try2optimize) {
6246 /* Maybe we can optimize this:
6247 * if pattern ends with unescaped *, we can avoid checking
6248 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6249 * it wont match truncated "raw_value_of_" strings too.
6250 */
6251 unsigned plen = strlen(pattern);
6252 /* Does it end with "*"? */
6253 if (plen != 0 && pattern[--plen] == '*') {
6254 /* "xxxx*" is not escaped */
6255 /* "xxx\*" is escaped */
6256 /* "xx\\*" is not escaped */
6257 /* "x\\\*" is escaped */
6258 int slashes = 0;
6259 while (plen != 0 && pattern[--plen] == '\\')
6260 slashes++;
6261 if (!(slashes & 1))
6262 break; /* ends with unescaped "*" */
6263 }
6264 try2optimize = 0;
6265 }
6266#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006267 loc--;
6268 if (quotes) {
6269 if (--esc < 0) {
6270 esc = esclen(startp, loc);
6271 }
6272 if (esc % 2) {
6273 esc--;
6274 loc--;
6275 }
6276 }
6277 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006278 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006279}
6280
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006281static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006282static void
6283varunset(const char *end, const char *var, const char *umsg, int varflags)
6284{
6285 const char *msg;
6286 const char *tail;
6287
6288 tail = nullstr;
6289 msg = "parameter not set";
6290 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006291 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292 if (varflags & VSNUL)
6293 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006294 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006295 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006296 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006297 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006298 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006299}
6300
6301static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006302subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006303 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006304{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006305 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006306 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307 char *startp;
6308 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006309 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006310 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006311 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006312 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006313 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006314 int amount, resetloc;
6315 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006316 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006317 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006318
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006319 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6320 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006321
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006322 herefd = -1;
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006323 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006324 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6325 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006326 STPUTC('\0', expdest);
6327 herefd = saveherefd;
6328 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006329 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006330
6331 switch (subtype) {
6332 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006333 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006334 amount = startp - expdest;
6335 STADJUST(amount, expdest);
6336 return startp;
6337
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006338 case VSQUESTION:
6339 varunset(p, varname, startp, varflags);
6340 /* NOTREACHED */
6341
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006342#if ENABLE_ASH_BASH_COMPAT
6343 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006344//TODO: support more general format ${v:EXPR:EXPR},
6345// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006346 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006347 /* Read POS in ${var:POS:LEN} */
6348 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006349 len = str - startp - 1;
6350
6351 /* *loc != '\0', guaranteed by parser */
6352 if (quotes) {
6353 char *ptr;
6354
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006355 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006356 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006357 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006358 len--;
6359 ptr++;
6360 }
6361 }
6362 }
6363 orig_len = len;
6364
6365 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006366 /* ${var::LEN} */
6367 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006368 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006369 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006370 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006371 while (*loc && *loc != ':') {
6372 /* TODO?
6373 * bash complains on: var=qwe; echo ${var:1a:123}
6374 if (!isdigit(*loc))
6375 ash_msg_and_raise_error(msg_illnum, str);
6376 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006377 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006378 }
6379 if (*loc++ == ':') {
6380 len = number(loc);
6381 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006382 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006383 if (pos < 0) {
6384 /* ${VAR:$((-n)):l} starts n chars from the end */
6385 pos = orig_len + pos;
6386 }
6387 if ((unsigned)pos >= orig_len) {
6388 /* apart from obvious ${VAR:999999:l},
6389 * covers ${VAR:$((-9999999)):l} - result is ""
6390 * (bash-compat)
6391 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006392 pos = 0;
6393 len = 0;
6394 }
6395 if (len > (orig_len - pos))
6396 len = orig_len - pos;
6397
6398 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006399 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006400 str++;
6401 }
6402 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006403 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006404 *loc++ = *str++;
6405 *loc++ = *str++;
6406 }
6407 *loc = '\0';
6408 amount = loc - expdest;
6409 STADJUST(amount, expdest);
6410 return loc;
6411#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006412 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006413
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006414 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006415
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006416 /* We'll comeback here if we grow the stack while handling
6417 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6418 * stack will need rebasing, and we'll need to remove our work
6419 * areas each time
6420 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006421 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006422
6423 amount = expdest - ((char *)stackblock() + resetloc);
6424 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006425 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006426
6427 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006428 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006430 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006431 if (rmesc != startp) {
6432 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006433 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006434 }
6435 }
6436 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006437 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006438 /*
6439 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6440 * The result is a_\_z_c (not a\_\_z_c)!
6441 *
6442 * The search pattern and replace string treat backslashes differently!
6443 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6444 * and string. It's only used on the first call.
6445 */
6446 preglob(str, IF_ASH_BASH_COMPAT(
6447 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6448 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006449
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006450#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006451 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006452 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006453 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006454
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006455 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006456 repl = strchr(str, CTLESC);
6457 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006458 *repl++ = '\0';
6459 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006460 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006461 }
Ron Yorston417622c2015-05-18 09:59:14 +02006462 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006463
6464 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006465 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006466 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006467
6468 len = 0;
6469 idx = startp;
6470 end = str - 1;
6471 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006472 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006473 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006474 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006475 if (!loc) {
6476 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006477 char *restart_detect = stackblock();
6478 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006479 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006480 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006481 idx++;
6482 len++;
6483 STPUTC(*idx, expdest);
6484 }
6485 if (stackblock() != restart_detect)
6486 goto restart;
6487 idx++;
6488 len++;
6489 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006490 /* continue; - prone to quadratic behavior, smarter code: */
6491 if (idx >= end)
6492 break;
6493 if (str[0] == '*') {
6494 /* Pattern is "*foo". If "*foo" does not match "long_string",
6495 * it would never match "ong_string" etc, no point in trying.
6496 */
6497 goto skip_matching;
6498 }
6499 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006500 }
6501
6502 if (subtype == VSREPLACEALL) {
6503 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006504 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006505 idx++;
6506 idx++;
6507 rmesc++;
6508 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006509 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006510 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006511 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006512
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006513 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006514 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006515 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006516 if (quotes && *loc == '\\') {
6517 STPUTC(CTLESC, expdest);
6518 len++;
6519 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006520 STPUTC(*loc, expdest);
6521 if (stackblock() != restart_detect)
6522 goto restart;
6523 len++;
6524 }
6525
6526 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006527 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006528 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006529 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006530 STPUTC(*idx, expdest);
6531 if (stackblock() != restart_detect)
6532 goto restart;
6533 len++;
6534 idx++;
6535 }
6536 break;
6537 }
6538 }
6539
6540 /* We've put the replaced text into a buffer at workloc, now
6541 * move it to the right place and adjust the stack.
6542 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006543 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006544 startp = (char *)stackblock() + startloc;
6545 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006546 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006547 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006548 STADJUST(-amount, expdest);
6549 return startp;
6550 }
6551#endif /* ENABLE_ASH_BASH_COMPAT */
6552
6553 subtype -= VSTRIMRIGHT;
6554#if DEBUG
6555 if (subtype < 0 || subtype > 7)
6556 abort();
6557#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006558 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006559 zero = subtype >> 1;
6560 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6561 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6562
6563 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6564 if (loc) {
6565 if (zero) {
6566 memmove(startp, loc, str - loc);
6567 loc = startp + (str - loc) - 1;
6568 }
6569 *loc = '\0';
6570 amount = loc - expdest;
6571 STADJUST(amount, expdest);
6572 }
6573 return loc;
6574}
6575
6576/*
6577 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006578 * name parameter (examples):
6579 * ash -c 'echo $1' name:'1='
6580 * ash -c 'echo $qwe' name:'qwe='
6581 * ash -c 'echo $$' name:'$='
6582 * ash -c 'echo ${$}' name:'$='
6583 * ash -c 'echo ${$##q}' name:'$=q'
6584 * ash -c 'echo ${#$}' name:'$='
6585 * note: examples with bad shell syntax:
6586 * ash -c 'echo ${#$1}' name:'$=1'
6587 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006588 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006589static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006590varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006591{
Mike Frysinger98c52642009-04-02 10:02:37 +00006592 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006593 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006594 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006595 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006596 int sep;
Ron Yorston549deab2015-05-18 09:57:51 +02006597 int quoted = flags & EXP_QUOTED;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006598 int subtype = varflags & VSTYPE;
6599 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6600 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006601 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006603 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
6604
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006605 switch (*name) {
6606 case '$':
6607 num = rootpid;
6608 goto numvar;
6609 case '?':
6610 num = exitstatus;
6611 goto numvar;
6612 case '#':
6613 num = shellparam.nparam;
6614 goto numvar;
6615 case '!':
6616 num = backgndpid;
6617 if (num == 0)
6618 return -1;
6619 numvar:
6620 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006621 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006622 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006623 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006624 for (i = NOPTS - 1; i >= 0; i--) {
6625 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006626 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006627 len++;
6628 }
6629 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006630 check_1char_name:
6631#if 0
6632 /* handles cases similar to ${#$1} */
6633 if (name[2] != '\0')
6634 raise_error_syntax("bad substitution");
6635#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006636 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006637 case '@': {
6638 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006639 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006640
6641 if (quoted && (flags & EXP_FULL)) {
6642 /* note: this is not meant as PEOF value */
6643 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006644 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006645 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006646 /* fall through */
6647 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006648 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006649 param:
6650 ap = shellparam.p;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006651 sepc = sep;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006652 if (!ap)
6653 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006654 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006655 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006656
6657 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006658 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006659 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006660 }
6661 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006662 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006663 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006664 case '0':
6665 case '1':
6666 case '2':
6667 case '3':
6668 case '4':
6669 case '5':
6670 case '6':
6671 case '7':
6672 case '8':
6673 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006674 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006675 if (num < 0 || num > shellparam.nparam)
6676 return -1;
6677 p = num ? shellparam.p[num - 1] : arg0;
6678 goto value;
6679 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006680 /* NB: name has form "VAR=..." */
6681
6682 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6683 * which should be considered before we check variables. */
6684 if (var_str_list) {
6685 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6686 p = NULL;
6687 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006688 char *str, *eq;
6689 str = var_str_list->text;
6690 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006691 if (!eq) /* stop at first non-assignment */
6692 break;
6693 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006694 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006695 && strncmp(str, name, name_len) == 0
6696 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006697 p = eq;
6698 /* goto value; - WRONG! */
6699 /* think "A=1 A=2 B=$A" */
6700 }
6701 var_str_list = var_str_list->next;
6702 } while (var_str_list);
6703 if (p)
6704 goto value;
6705 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006706 p = lookupvar(name);
6707 value:
6708 if (!p)
6709 return -1;
6710
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006711 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006712#if ENABLE_UNICODE_SUPPORT
6713 if (subtype == VSLENGTH && len > 0) {
6714 reinit_unicode_for_ash();
6715 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006716 STADJUST(-len, expdest);
6717 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006718 len = unicode_strlen(p);
6719 }
6720 }
6721#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006722 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006723 }
6724
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006725 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006726 STADJUST(-len, expdest);
6727 return len;
6728}
6729
6730/*
6731 * Expand a variable, and return a pointer to the next character in the
6732 * input string.
6733 */
6734static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006735evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006736{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006737 char varflags;
6738 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006739 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006740 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006741 char *var;
6742 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006743 int startloc;
6744 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006745
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006746 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006747 subtype = varflags & VSTYPE;
Ron Yorston549deab2015-05-18 09:57:51 +02006748 quoted = flags & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006749 var = p;
6750 easy = (!quoted || (*var == '@' && shellparam.nparam));
6751 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006752 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006753
6754 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006755 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006756 if (varflags & VSNUL)
6757 varlen--;
6758
6759 if (subtype == VSPLUS) {
6760 varlen = -1 - varlen;
6761 goto vsplus;
6762 }
6763
6764 if (subtype == VSMINUS) {
6765 vsplus:
6766 if (varlen < 0) {
6767 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006768 p,
Ron Yorston549deab2015-05-18 09:57:51 +02006769 flags | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006770 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006771 );
6772 goto end;
6773 }
6774 if (easy)
6775 goto record;
6776 goto end;
6777 }
6778
6779 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6780 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006781 if (subevalvar(p, var, /* strloc: */ 0,
6782 subtype, startloc, varflags,
Ron Yorston549deab2015-05-18 09:57:51 +02006783 /* quotes: */ flags & ~QUOTES_ESC,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006784 var_str_list)
6785 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006786 varflags &= ~VSNUL;
6787 /*
6788 * Remove any recorded regions beyond
6789 * start of variable
6790 */
6791 removerecordregions(startloc);
6792 goto again;
6793 }
6794 goto end;
6795 }
6796 if (easy)
6797 goto record;
6798 goto end;
6799 }
6800
6801 if (varlen < 0 && uflag)
6802 varunset(p, var, 0, 0);
6803
6804 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006805 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006806 goto record;
6807 }
6808
6809 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006810 if (easy)
6811 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006812 goto end;
6813 }
6814
6815#if DEBUG
6816 switch (subtype) {
6817 case VSTRIMLEFT:
6818 case VSTRIMLEFTMAX:
6819 case VSTRIMRIGHT:
6820 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006821#if ENABLE_ASH_BASH_COMPAT
6822 case VSSUBSTR:
6823 case VSREPLACE:
6824 case VSREPLACEALL:
6825#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006826 break;
6827 default:
6828 abort();
6829 }
6830#endif
6831
6832 if (varlen >= 0) {
6833 /*
6834 * Terminate the string and start recording the pattern
6835 * right after it
6836 */
6837 STPUTC('\0', expdest);
6838 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006839 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006840 startloc, varflags, flags, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006841 int amount = expdest - (
6842 (char *)stackblock() + patloc - 1
6843 );
6844 STADJUST(-amount, expdest);
6845 }
6846 /* Remove any recorded regions beyond start of variable */
6847 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006848 record:
6849 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006850 }
6851
6852 end:
6853 if (subtype != VSNORMAL) { /* skip to end of alternative */
6854 int nesting = 1;
6855 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006856 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006857 if (c == CTLESC)
6858 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006859 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006860 if (varlen >= 0)
6861 argbackq = argbackq->next;
6862 } else if (c == CTLVAR) {
6863 if ((*p++ & VSTYPE) != VSNORMAL)
6864 nesting++;
6865 } else if (c == CTLENDVAR) {
6866 if (--nesting == 0)
6867 break;
6868 }
6869 }
6870 }
6871 return p;
6872}
6873
6874/*
6875 * Break the argument string into pieces based upon IFS and add the
6876 * strings to the argument list. The regions of the string to be
6877 * searched for IFS characters have been stored by recordregion.
6878 */
6879static void
6880ifsbreakup(char *string, struct arglist *arglist)
6881{
6882 struct ifsregion *ifsp;
6883 struct strlist *sp;
6884 char *start;
6885 char *p;
6886 char *q;
6887 const char *ifs, *realifs;
6888 int ifsspc;
6889 int nulonly;
6890
6891 start = string;
6892 if (ifslastp != NULL) {
6893 ifsspc = 0;
6894 nulonly = 0;
6895 realifs = ifsset() ? ifsval() : defifs;
6896 ifsp = &ifsfirst;
6897 do {
6898 p = string + ifsp->begoff;
6899 nulonly = ifsp->nulonly;
6900 ifs = nulonly ? nullstr : realifs;
6901 ifsspc = 0;
6902 while (p < string + ifsp->endoff) {
6903 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006904 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006905 p++;
6906 if (!strchr(ifs, *p)) {
6907 p++;
6908 continue;
6909 }
6910 if (!nulonly)
6911 ifsspc = (strchr(defifs, *p) != NULL);
6912 /* Ignore IFS whitespace at start */
6913 if (q == start && ifsspc) {
6914 p++;
6915 start = p;
6916 continue;
6917 }
6918 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006919 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006920 sp->text = start;
6921 *arglist->lastp = sp;
6922 arglist->lastp = &sp->next;
6923 p++;
6924 if (!nulonly) {
6925 for (;;) {
6926 if (p >= string + ifsp->endoff) {
6927 break;
6928 }
6929 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006930 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006931 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006932 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006933 p = q;
6934 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006935 }
6936 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006937 if (ifsspc) {
6938 p++;
6939 ifsspc = 0;
6940 } else {
6941 p = q;
6942 break;
6943 }
6944 } else
6945 p++;
6946 }
6947 }
6948 start = p;
6949 } /* while */
6950 ifsp = ifsp->next;
6951 } while (ifsp != NULL);
6952 if (nulonly)
6953 goto add;
6954 }
6955
6956 if (!*start)
6957 return;
6958
6959 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006960 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006961 sp->text = start;
6962 *arglist->lastp = sp;
6963 arglist->lastp = &sp->next;
6964}
6965
6966static void
6967ifsfree(void)
6968{
6969 struct ifsregion *p;
6970
6971 INT_OFF;
6972 p = ifsfirst.next;
6973 do {
6974 struct ifsregion *ifsp;
6975 ifsp = p->next;
6976 free(p);
6977 p = ifsp;
6978 } while (p);
6979 ifslastp = NULL;
6980 ifsfirst.next = NULL;
6981 INT_ON;
6982}
6983
6984/*
6985 * Add a file name to the list.
6986 */
6987static void
6988addfname(const char *name)
6989{
6990 struct strlist *sp;
6991
Denis Vlasenko597906c2008-02-20 16:38:54 +00006992 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02006993 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006994 *exparg.lastp = sp;
6995 exparg.lastp = &sp->next;
6996}
6997
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006998/* If we want to use glob() from libc... */
6999#if 1
7000
7001/* Add the result of glob() to the list */
7002static void
7003addglob(const glob_t *pglob)
7004{
7005 char **p = pglob->gl_pathv;
7006
7007 do {
7008 addfname(*p);
7009 } while (*++p);
7010}
7011static void
7012expandmeta(struct strlist *str /*, int flag*/)
7013{
7014 /* TODO - EXP_REDIR */
7015
7016 while (str) {
7017 char *p;
7018 glob_t pglob;
7019 int i;
7020
7021 if (fflag)
7022 goto nometa;
7023 INT_OFF;
7024 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7025 /*
7026 * GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7027 * TODO?: GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7028 */
7029 i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7030 if (p != str->text)
7031 free(p);
7032 switch (i) {
7033 case 0:
7034 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7035 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7036 goto nometa2;
7037 addglob(&pglob);
7038 globfree(&pglob);
7039 INT_ON;
7040 break;
7041 case GLOB_NOMATCH:
7042nometa2:
7043 globfree(&pglob);
7044 INT_ON;
7045nometa:
7046 *exparg.lastp = str;
7047 rmescapes(str->text, 0);
7048 exparg.lastp = &str->next;
7049 break;
7050 default: /* GLOB_NOSPACE */
7051 globfree(&pglob);
7052 INT_ON;
7053 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7054 }
7055 str = str->next;
7056 }
7057}
7058
7059#else
7060/* Homegrown globbing code. (dash also has both, uses homegrown one.) */
7061
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007062/*
7063 * Do metacharacter (i.e. *, ?, [...]) expansion.
7064 */
7065static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007066expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007067{
7068 char *p;
7069 const char *cp;
7070 char *start;
7071 char *endname;
7072 int metaflag;
7073 struct stat statb;
7074 DIR *dirp;
7075 struct dirent *dp;
7076 int atend;
7077 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007078 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007079
7080 metaflag = 0;
7081 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007082 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007083 if (*p == '*' || *p == '?')
7084 metaflag = 1;
7085 else if (*p == '[') {
7086 char *q = p + 1;
7087 if (*q == '!')
7088 q++;
7089 for (;;) {
7090 if (*q == '\\')
7091 q++;
7092 if (*q == '/' || *q == '\0')
7093 break;
7094 if (*++q == ']') {
7095 metaflag = 1;
7096 break;
7097 }
7098 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007099 } else {
7100 if (*p == '\\')
7101 esc++;
7102 if (p[esc] == '/') {
7103 if (metaflag)
7104 break;
7105 start = p + esc + 1;
7106 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007107 }
7108 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007109 if (metaflag == 0) { /* we've reached the end of the file name */
7110 if (enddir != expdir)
7111 metaflag++;
7112 p = name;
7113 do {
7114 if (*p == '\\')
7115 p++;
7116 *enddir++ = *p;
7117 } while (*p++);
7118 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7119 addfname(expdir);
7120 return;
7121 }
7122 endname = p;
7123 if (name < start) {
7124 p = name;
7125 do {
7126 if (*p == '\\')
7127 p++;
7128 *enddir++ = *p++;
7129 } while (p < start);
7130 }
7131 if (enddir == expdir) {
7132 cp = ".";
7133 } else if (enddir == expdir + 1 && *expdir == '/') {
7134 cp = "/";
7135 } else {
7136 cp = expdir;
7137 enddir[-1] = '\0';
7138 }
7139 dirp = opendir(cp);
7140 if (dirp == NULL)
7141 return;
7142 if (enddir != expdir)
7143 enddir[-1] = '/';
7144 if (*endname == 0) {
7145 atend = 1;
7146 } else {
7147 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007148 *endname = '\0';
7149 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007150 }
7151 matchdot = 0;
7152 p = start;
7153 if (*p == '\\')
7154 p++;
7155 if (*p == '.')
7156 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007157 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007158 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007159 continue;
7160 if (pmatch(start, dp->d_name)) {
7161 if (atend) {
7162 strcpy(enddir, dp->d_name);
7163 addfname(expdir);
7164 } else {
7165 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7166 continue;
7167 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007168 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007169 }
7170 }
7171 }
7172 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007173 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007174 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007175}
7176
7177static struct strlist *
7178msort(struct strlist *list, int len)
7179{
7180 struct strlist *p, *q = NULL;
7181 struct strlist **lpp;
7182 int half;
7183 int n;
7184
7185 if (len <= 1)
7186 return list;
7187 half = len >> 1;
7188 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007189 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007190 q = p;
7191 p = p->next;
7192 }
7193 q->next = NULL; /* terminate first half of list */
7194 q = msort(list, half); /* sort first half of list */
7195 p = msort(p, len - half); /* sort second half */
7196 lpp = &list;
7197 for (;;) {
7198#if ENABLE_LOCALE_SUPPORT
7199 if (strcoll(p->text, q->text) < 0)
7200#else
7201 if (strcmp(p->text, q->text) < 0)
7202#endif
7203 {
7204 *lpp = p;
7205 lpp = &p->next;
7206 p = *lpp;
7207 if (p == NULL) {
7208 *lpp = q;
7209 break;
7210 }
7211 } else {
7212 *lpp = q;
7213 lpp = &q->next;
7214 q = *lpp;
7215 if (q == NULL) {
7216 *lpp = p;
7217 break;
7218 }
7219 }
7220 }
7221 return list;
7222}
7223
7224/*
7225 * Sort the results of file name expansion. It calculates the number of
7226 * strings to sort and then calls msort (short for merge sort) to do the
7227 * work.
7228 */
7229static struct strlist *
7230expsort(struct strlist *str)
7231{
7232 int len;
7233 struct strlist *sp;
7234
7235 len = 0;
7236 for (sp = str; sp; sp = sp->next)
7237 len++;
7238 return msort(str, len);
7239}
7240
7241static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007242expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007243{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007244 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007245 '*', '?', '[', 0
7246 };
7247 /* TODO - EXP_REDIR */
7248
7249 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007250 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007251 struct strlist **savelastp;
7252 struct strlist *sp;
7253 char *p;
7254
7255 if (fflag)
7256 goto nometa;
7257 if (!strpbrk(str->text, metachars))
7258 goto nometa;
7259 savelastp = exparg.lastp;
7260
7261 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007262 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007263 {
7264 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007265//BUGGY estimation of how long expanded name can be
7266 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007267 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007268 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007269 free(expdir);
7270 if (p != str->text)
7271 free(p);
7272 INT_ON;
7273 if (exparg.lastp == savelastp) {
7274 /*
7275 * no matches
7276 */
7277 nometa:
7278 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007279 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007280 exparg.lastp = &str->next;
7281 } else {
7282 *exparg.lastp = NULL;
7283 *savelastp = sp = expsort(*savelastp);
7284 while (sp->next != NULL)
7285 sp = sp->next;
7286 exparg.lastp = &sp->next;
7287 }
7288 str = str->next;
7289 }
7290}
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007291#endif /* our globbing code */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007292
7293/*
7294 * Perform variable substitution and command substitution on an argument,
7295 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7296 * perform splitting and file name expansion. When arglist is NULL, perform
7297 * here document expansion.
7298 */
7299static void
7300expandarg(union node *arg, struct arglist *arglist, int flag)
7301{
7302 struct strlist *sp;
7303 char *p;
7304
7305 argbackq = arg->narg.backquote;
7306 STARTSTACKSTR(expdest);
7307 ifsfirst.next = NULL;
7308 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007309 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007310 argstr(arg->narg.text, flag,
7311 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007312 p = _STPUTC('\0', expdest);
7313 expdest = p - 1;
7314 if (arglist == NULL) {
7315 return; /* here document expanded */
7316 }
7317 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007318 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007319 exparg.lastp = &exparg.list;
7320 /*
7321 * TODO - EXP_REDIR
7322 */
7323 if (flag & EXP_FULL) {
7324 ifsbreakup(p, &exparg);
7325 *exparg.lastp = NULL;
7326 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007327 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007328 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007329 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007330 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007331 TRACE(("expandarg: rmescapes:'%s'\n", p));
7332 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007333 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007334 sp->text = p;
7335 *exparg.lastp = sp;
7336 exparg.lastp = &sp->next;
7337 }
7338 if (ifsfirst.next)
7339 ifsfree();
7340 *exparg.lastp = NULL;
7341 if (exparg.list) {
7342 *arglist->lastp = exparg.list;
7343 arglist->lastp = exparg.lastp;
7344 }
7345}
7346
7347/*
7348 * Expand shell variables and backquotes inside a here document.
7349 */
7350static void
7351expandhere(union node *arg, int fd)
7352{
7353 herefd = fd;
Ron Yorston549deab2015-05-18 09:57:51 +02007354 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007355 full_write(fd, stackblock(), expdest - (char *)stackblock());
7356}
7357
7358/*
7359 * Returns true if the pattern matches the string.
7360 */
7361static int
7362patmatch(char *pattern, const char *string)
7363{
Ron Yorston549deab2015-05-18 09:57:51 +02007364 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007365}
7366
7367/*
7368 * See if a pattern matches in a case statement.
7369 */
7370static int
7371casematch(union node *pattern, char *val)
7372{
7373 struct stackmark smark;
7374 int result;
7375
7376 setstackmark(&smark);
7377 argbackq = pattern->narg.backquote;
7378 STARTSTACKSTR(expdest);
7379 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007380 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7381 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007382 STACKSTRNUL(expdest);
7383 result = patmatch(stackblock(), val);
7384 popstackmark(&smark);
7385 return result;
7386}
7387
7388
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007389/* ============ find_command */
7390
7391struct builtincmd {
7392 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007393 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007394 /* unsigned flags; */
7395};
7396#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007397/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007398 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007399#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007400#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007401
7402struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007403 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007404 union param {
7405 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007406 /* index >= 0 for commands without path (slashes) */
7407 /* (TODO: what exactly does the value mean? PATH position?) */
7408 /* index == -1 for commands with slashes */
7409 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007410 const struct builtincmd *cmd;
7411 struct funcnode *func;
7412 } u;
7413};
7414/* values of cmdtype */
7415#define CMDUNKNOWN -1 /* no entry in table for command */
7416#define CMDNORMAL 0 /* command is an executable program */
7417#define CMDFUNCTION 1 /* command is a shell function */
7418#define CMDBUILTIN 2 /* command is a shell builtin */
7419
7420/* action to find_command() */
7421#define DO_ERR 0x01 /* prints errors */
7422#define DO_ABS 0x02 /* checks absolute paths */
7423#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7424#define DO_ALTPATH 0x08 /* using alternate path */
7425#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7426
7427static void find_command(char *, struct cmdentry *, int, const char *);
7428
7429
7430/* ============ Hashing commands */
7431
7432/*
7433 * When commands are first encountered, they are entered in a hash table.
7434 * This ensures that a full path search will not have to be done for them
7435 * on each invocation.
7436 *
7437 * We should investigate converting to a linear search, even though that
7438 * would make the command name "hash" a misnomer.
7439 */
7440
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007441struct tblentry {
7442 struct tblentry *next; /* next entry in hash chain */
7443 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007444 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007445 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007446 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007447};
7448
Denis Vlasenko01631112007-12-16 17:20:38 +00007449static struct tblentry **cmdtable;
7450#define INIT_G_cmdtable() do { \
7451 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7452} while (0)
7453
7454static int builtinloc = -1; /* index in path of %builtin, or -1 */
7455
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007456
7457static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007458tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007459{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007460#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007461 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007462 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007463 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007464 while (*envp)
7465 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007466 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007467 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007468 /* re-exec ourselves with the new arguments */
7469 execve(bb_busybox_exec_path, argv, envp);
7470 /* If they called chroot or otherwise made the binary no longer
7471 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007472 }
7473#endif
7474
7475 repeat:
7476#ifdef SYSV
7477 do {
7478 execve(cmd, argv, envp);
7479 } while (errno == EINTR);
7480#else
7481 execve(cmd, argv, envp);
7482#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007483 if (cmd == (char*) bb_busybox_exec_path) {
7484 /* We already visited ENOEXEC branch below, don't do it again */
7485//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007486 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007487 return;
7488 }
7489 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007490 /* Run "cmd" as a shell script:
7491 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7492 * "If the execve() function fails with ENOEXEC, the shell
7493 * shall execute a command equivalent to having a shell invoked
7494 * with the command name as its first operand,
7495 * with any remaining arguments passed to the new shell"
7496 *
7497 * That is, do not use $SHELL, user's shell, or /bin/sh;
7498 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007499 *
7500 * Note that bash reads ~80 chars of the file, and if it sees
7501 * a zero byte before it sees newline, it doesn't try to
7502 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007503 * message and exit code 126. For one, this prevents attempts
7504 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007505 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007506 char **ap;
7507 char **new;
7508
7509 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007510 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007511 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7512 new[0] = (char*) "ash";
7513 new[1] = cmd;
7514 ap = new + 2;
7515 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007516 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007517 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007518 argv = new;
7519 goto repeat;
7520 }
7521}
7522
7523/*
7524 * Exec a program. Never returns. If you change this routine, you may
7525 * have to change the find_command routine as well.
7526 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007527static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007528static void
7529shellexec(char **argv, const char *path, int idx)
7530{
7531 char *cmdname;
7532 int e;
7533 char **envp;
7534 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007535 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007536
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007537 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007538 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007539 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007540#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007541 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007542#endif
7543 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007544 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007545 if (applet_no >= 0) {
7546 /* We tried execing ourself, but it didn't work.
7547 * Maybe /proc/self/exe doesn't exist?
7548 * Try $PATH search.
7549 */
7550 goto try_PATH;
7551 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007552 e = errno;
7553 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007554 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007555 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007556 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007557 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007558 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007559 if (errno != ENOENT && errno != ENOTDIR)
7560 e = errno;
7561 }
7562 stunalloc(cmdname);
7563 }
7564 }
7565
7566 /* Map to POSIX errors */
7567 switch (e) {
7568 case EACCES:
7569 exerrno = 126;
7570 break;
7571 case ENOENT:
7572 exerrno = 127;
7573 break;
7574 default:
7575 exerrno = 2;
7576 break;
7577 }
7578 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007579 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7580 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007581 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7582 /* NOTREACHED */
7583}
7584
7585static void
7586printentry(struct tblentry *cmdp)
7587{
7588 int idx;
7589 const char *path;
7590 char *name;
7591
7592 idx = cmdp->param.index;
7593 path = pathval();
7594 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007595 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007596 stunalloc(name);
7597 } while (--idx >= 0);
7598 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7599}
7600
7601/*
7602 * Clear out command entries. The argument specifies the first entry in
7603 * PATH which has changed.
7604 */
7605static void
7606clearcmdentry(int firstchange)
7607{
7608 struct tblentry **tblp;
7609 struct tblentry **pp;
7610 struct tblentry *cmdp;
7611
7612 INT_OFF;
7613 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7614 pp = tblp;
7615 while ((cmdp = *pp) != NULL) {
7616 if ((cmdp->cmdtype == CMDNORMAL &&
7617 cmdp->param.index >= firstchange)
7618 || (cmdp->cmdtype == CMDBUILTIN &&
7619 builtinloc >= firstchange)
7620 ) {
7621 *pp = cmdp->next;
7622 free(cmdp);
7623 } else {
7624 pp = &cmdp->next;
7625 }
7626 }
7627 }
7628 INT_ON;
7629}
7630
7631/*
7632 * Locate a command in the command hash table. If "add" is nonzero,
7633 * add the command to the table if it is not already present. The
7634 * variable "lastcmdentry" is set to point to the address of the link
7635 * pointing to the entry, so that delete_cmd_entry can delete the
7636 * entry.
7637 *
7638 * Interrupts must be off if called with add != 0.
7639 */
7640static struct tblentry **lastcmdentry;
7641
7642static struct tblentry *
7643cmdlookup(const char *name, int add)
7644{
7645 unsigned int hashval;
7646 const char *p;
7647 struct tblentry *cmdp;
7648 struct tblentry **pp;
7649
7650 p = name;
7651 hashval = (unsigned char)*p << 4;
7652 while (*p)
7653 hashval += (unsigned char)*p++;
7654 hashval &= 0x7FFF;
7655 pp = &cmdtable[hashval % CMDTABLESIZE];
7656 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7657 if (strcmp(cmdp->cmdname, name) == 0)
7658 break;
7659 pp = &cmdp->next;
7660 }
7661 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007662 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7663 + strlen(name)
7664 /* + 1 - already done because
7665 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007666 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007667 cmdp->cmdtype = CMDUNKNOWN;
7668 strcpy(cmdp->cmdname, name);
7669 }
7670 lastcmdentry = pp;
7671 return cmdp;
7672}
7673
7674/*
7675 * Delete the command entry returned on the last lookup.
7676 */
7677static void
7678delete_cmd_entry(void)
7679{
7680 struct tblentry *cmdp;
7681
7682 INT_OFF;
7683 cmdp = *lastcmdentry;
7684 *lastcmdentry = cmdp->next;
7685 if (cmdp->cmdtype == CMDFUNCTION)
7686 freefunc(cmdp->param.func);
7687 free(cmdp);
7688 INT_ON;
7689}
7690
7691/*
7692 * Add a new command entry, replacing any existing command entry for
7693 * the same name - except special builtins.
7694 */
7695static void
7696addcmdentry(char *name, struct cmdentry *entry)
7697{
7698 struct tblentry *cmdp;
7699
7700 cmdp = cmdlookup(name, 1);
7701 if (cmdp->cmdtype == CMDFUNCTION) {
7702 freefunc(cmdp->param.func);
7703 }
7704 cmdp->cmdtype = entry->cmdtype;
7705 cmdp->param = entry->u;
7706 cmdp->rehash = 0;
7707}
7708
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007709static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007710hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007711{
7712 struct tblentry **pp;
7713 struct tblentry *cmdp;
7714 int c;
7715 struct cmdentry entry;
7716 char *name;
7717
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007718 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007719 clearcmdentry(0);
7720 return 0;
7721 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007722
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007723 if (*argptr == NULL) {
7724 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7725 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7726 if (cmdp->cmdtype == CMDNORMAL)
7727 printentry(cmdp);
7728 }
7729 }
7730 return 0;
7731 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007732
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007733 c = 0;
7734 while ((name = *argptr) != NULL) {
7735 cmdp = cmdlookup(name, 0);
7736 if (cmdp != NULL
7737 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007738 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7739 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007740 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007741 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007742 find_command(name, &entry, DO_ERR, pathval());
7743 if (entry.cmdtype == CMDUNKNOWN)
7744 c = 1;
7745 argptr++;
7746 }
7747 return c;
7748}
7749
7750/*
7751 * Called when a cd is done. Marks all commands so the next time they
7752 * are executed they will be rehashed.
7753 */
7754static void
7755hashcd(void)
7756{
7757 struct tblentry **pp;
7758 struct tblentry *cmdp;
7759
7760 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7761 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007762 if (cmdp->cmdtype == CMDNORMAL
7763 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007764 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007765 && builtinloc > 0)
7766 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007767 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007768 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007769 }
7770 }
7771}
7772
7773/*
7774 * Fix command hash table when PATH changed.
7775 * Called before PATH is changed. The argument is the new value of PATH;
7776 * pathval() still returns the old value at this point.
7777 * Called with interrupts off.
7778 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007779static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007780changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007781{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007782 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007783 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007784 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007785 int idx_bltin;
7786
7787 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007788 firstchange = 9999; /* assume no change */
7789 idx = 0;
7790 idx_bltin = -1;
7791 for (;;) {
7792 if (*old != *new) {
7793 firstchange = idx;
7794 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007795 || (*old == ':' && *new == '\0')
7796 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007797 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007798 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007799 old = new; /* ignore subsequent differences */
7800 }
7801 if (*new == '\0')
7802 break;
7803 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7804 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007805 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007806 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007807 new++;
7808 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007809 }
7810 if (builtinloc < 0 && idx_bltin >= 0)
7811 builtinloc = idx_bltin; /* zap builtins */
7812 if (builtinloc >= 0 && idx_bltin < 0)
7813 firstchange = 0;
7814 clearcmdentry(firstchange);
7815 builtinloc = idx_bltin;
7816}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007817enum {
7818 TEOF,
7819 TNL,
7820 TREDIR,
7821 TWORD,
7822 TSEMI,
7823 TBACKGND,
7824 TAND,
7825 TOR,
7826 TPIPE,
7827 TLP,
7828 TRP,
7829 TENDCASE,
7830 TENDBQUOTE,
7831 TNOT,
7832 TCASE,
7833 TDO,
7834 TDONE,
7835 TELIF,
7836 TELSE,
7837 TESAC,
7838 TFI,
7839 TFOR,
7840#if ENABLE_ASH_BASH_COMPAT
7841 TFUNCTION,
7842#endif
7843 TIF,
7844 TIN,
7845 TTHEN,
7846 TUNTIL,
7847 TWHILE,
7848 TBEGIN,
7849 TEND
7850};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007851typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007852
7853/* first char is indicating which tokens mark the end of a list */
7854static const char *const tokname_array[] = {
7855 "\1end of file",
7856 "\0newline",
7857 "\0redirection",
7858 "\0word",
7859 "\0;",
7860 "\0&",
7861 "\0&&",
7862 "\0||",
7863 "\0|",
7864 "\0(",
7865 "\1)",
7866 "\1;;",
7867 "\1`",
7868#define KWDOFFSET 13
7869 /* the following are keywords */
7870 "\0!",
7871 "\0case",
7872 "\1do",
7873 "\1done",
7874 "\1elif",
7875 "\1else",
7876 "\1esac",
7877 "\1fi",
7878 "\0for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007879#if ENABLE_ASH_BASH_COMPAT
7880 "\0function",
7881#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007882 "\0if",
7883 "\0in",
7884 "\1then",
7885 "\0until",
7886 "\0while",
7887 "\0{",
7888 "\1}",
7889};
7890
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007891/* Wrapper around strcmp for qsort/bsearch/... */
7892static int
7893pstrcmp(const void *a, const void *b)
7894{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007895 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007896}
7897
7898static const char *const *
7899findkwd(const char *s)
7900{
7901 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007902 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7903 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007904}
7905
7906/*
7907 * Locate and print what a word is...
7908 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007909static int
Ron Yorston3f221112015-08-03 13:47:33 +01007910describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007911{
7912 struct cmdentry entry;
7913 struct tblentry *cmdp;
7914#if ENABLE_ASH_ALIAS
7915 const struct alias *ap;
7916#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007917
7918 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007919
7920 if (describe_command_verbose) {
7921 out1str(command);
7922 }
7923
7924 /* First look at the keywords */
7925 if (findkwd(command)) {
7926 out1str(describe_command_verbose ? " is a shell keyword" : command);
7927 goto out;
7928 }
7929
7930#if ENABLE_ASH_ALIAS
7931 /* Then look at the aliases */
7932 ap = lookupalias(command, 0);
7933 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007934 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007935 out1str("alias ");
7936 printalias(ap);
7937 return 0;
7938 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007939 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007940 goto out;
7941 }
7942#endif
7943 /* Then check if it is a tracked alias */
7944 cmdp = cmdlookup(command, 0);
7945 if (cmdp != NULL) {
7946 entry.cmdtype = cmdp->cmdtype;
7947 entry.u = cmdp->param;
7948 } else {
7949 /* Finally use brute force */
7950 find_command(command, &entry, DO_ABS, path);
7951 }
7952
7953 switch (entry.cmdtype) {
7954 case CMDNORMAL: {
7955 int j = entry.u.index;
7956 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007957 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007958 p = command;
7959 } else {
7960 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007961 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007962 stunalloc(p);
7963 } while (--j >= 0);
7964 }
7965 if (describe_command_verbose) {
7966 out1fmt(" is%s %s",
7967 (cmdp ? " a tracked alias for" : nullstr), p
7968 );
7969 } else {
7970 out1str(p);
7971 }
7972 break;
7973 }
7974
7975 case CMDFUNCTION:
7976 if (describe_command_verbose) {
7977 out1str(" is a shell function");
7978 } else {
7979 out1str(command);
7980 }
7981 break;
7982
7983 case CMDBUILTIN:
7984 if (describe_command_verbose) {
7985 out1fmt(" is a %sshell builtin",
7986 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7987 "special " : nullstr
7988 );
7989 } else {
7990 out1str(command);
7991 }
7992 break;
7993
7994 default:
7995 if (describe_command_verbose) {
7996 out1str(": not found\n");
7997 }
7998 return 127;
7999 }
8000 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008001 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008002 return 0;
8003}
8004
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008005static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008006typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008007{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008008 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008009 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008010 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008011
Denis Vlasenko46846e22007-05-20 13:08:31 +00008012 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008013 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008014 i++;
8015 verbose = 0;
8016 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008017 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008018 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008019 }
8020 return err;
8021}
8022
8023#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008024static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008025commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008026{
8027 int c;
8028 enum {
8029 VERIFY_BRIEF = 1,
8030 VERIFY_VERBOSE = 2,
8031 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008032 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008033
8034 while ((c = nextopt("pvV")) != '\0')
8035 if (c == 'V')
8036 verify |= VERIFY_VERBOSE;
8037 else if (c == 'v')
8038 verify |= VERIFY_BRIEF;
8039#if DEBUG
8040 else if (c != 'p')
8041 abort();
8042#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008043 else
8044 path = bb_default_path;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008045 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8046 if (verify && (*argptr != NULL)) {
Ron Yorston3f221112015-08-03 13:47:33 +01008047 return describe_command(*argptr, path, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008048 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008049
8050 return 0;
8051}
8052#endif
8053
8054
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008055/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00008056
Denis Vlasenko340299a2008-11-21 10:36:36 +00008057static int funcblocksize; /* size of structures in function */
8058static int funcstringsize; /* size of strings in node */
8059static void *funcblock; /* block to allocate function from */
8060static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008061
Eric Andersencb57d552001-06-28 07:25:16 +00008062/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008063#define EV_EXIT 01 /* exit after evaluating tree */
8064#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008065
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008066static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008067 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8068 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8069 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8070 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8071 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8072 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8073 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8074 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8075 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8076 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8077 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8078 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8079 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8080 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8081 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8082 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8083 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008084#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008085 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008086#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008087 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8088 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8089 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8090 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8091 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8092 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8093 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8094 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8095 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008096};
8097
8098static void calcsize(union node *n);
8099
8100static void
8101sizenodelist(struct nodelist *lp)
8102{
8103 while (lp) {
8104 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8105 calcsize(lp->n);
8106 lp = lp->next;
8107 }
8108}
8109
8110static void
8111calcsize(union node *n)
8112{
8113 if (n == NULL)
8114 return;
8115 funcblocksize += nodesize[n->type];
8116 switch (n->type) {
8117 case NCMD:
8118 calcsize(n->ncmd.redirect);
8119 calcsize(n->ncmd.args);
8120 calcsize(n->ncmd.assign);
8121 break;
8122 case NPIPE:
8123 sizenodelist(n->npipe.cmdlist);
8124 break;
8125 case NREDIR:
8126 case NBACKGND:
8127 case NSUBSHELL:
8128 calcsize(n->nredir.redirect);
8129 calcsize(n->nredir.n);
8130 break;
8131 case NAND:
8132 case NOR:
8133 case NSEMI:
8134 case NWHILE:
8135 case NUNTIL:
8136 calcsize(n->nbinary.ch2);
8137 calcsize(n->nbinary.ch1);
8138 break;
8139 case NIF:
8140 calcsize(n->nif.elsepart);
8141 calcsize(n->nif.ifpart);
8142 calcsize(n->nif.test);
8143 break;
8144 case NFOR:
8145 funcstringsize += strlen(n->nfor.var) + 1;
8146 calcsize(n->nfor.body);
8147 calcsize(n->nfor.args);
8148 break;
8149 case NCASE:
8150 calcsize(n->ncase.cases);
8151 calcsize(n->ncase.expr);
8152 break;
8153 case NCLIST:
8154 calcsize(n->nclist.body);
8155 calcsize(n->nclist.pattern);
8156 calcsize(n->nclist.next);
8157 break;
8158 case NDEFUN:
8159 case NARG:
8160 sizenodelist(n->narg.backquote);
8161 funcstringsize += strlen(n->narg.text) + 1;
8162 calcsize(n->narg.next);
8163 break;
8164 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008165#if ENABLE_ASH_BASH_COMPAT
8166 case NTO2:
8167#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008168 case NCLOBBER:
8169 case NFROM:
8170 case NFROMTO:
8171 case NAPPEND:
8172 calcsize(n->nfile.fname);
8173 calcsize(n->nfile.next);
8174 break;
8175 case NTOFD:
8176 case NFROMFD:
8177 calcsize(n->ndup.vname);
8178 calcsize(n->ndup.next);
8179 break;
8180 case NHERE:
8181 case NXHERE:
8182 calcsize(n->nhere.doc);
8183 calcsize(n->nhere.next);
8184 break;
8185 case NNOT:
8186 calcsize(n->nnot.com);
8187 break;
8188 };
8189}
8190
8191static char *
8192nodeckstrdup(char *s)
8193{
8194 char *rtn = funcstring;
8195
8196 strcpy(funcstring, s);
8197 funcstring += strlen(s) + 1;
8198 return rtn;
8199}
8200
8201static union node *copynode(union node *);
8202
8203static struct nodelist *
8204copynodelist(struct nodelist *lp)
8205{
8206 struct nodelist *start;
8207 struct nodelist **lpp;
8208
8209 lpp = &start;
8210 while (lp) {
8211 *lpp = funcblock;
8212 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8213 (*lpp)->n = copynode(lp->n);
8214 lp = lp->next;
8215 lpp = &(*lpp)->next;
8216 }
8217 *lpp = NULL;
8218 return start;
8219}
8220
8221static union node *
8222copynode(union node *n)
8223{
8224 union node *new;
8225
8226 if (n == NULL)
8227 return NULL;
8228 new = funcblock;
8229 funcblock = (char *) funcblock + nodesize[n->type];
8230
8231 switch (n->type) {
8232 case NCMD:
8233 new->ncmd.redirect = copynode(n->ncmd.redirect);
8234 new->ncmd.args = copynode(n->ncmd.args);
8235 new->ncmd.assign = copynode(n->ncmd.assign);
8236 break;
8237 case NPIPE:
8238 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008239 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008240 break;
8241 case NREDIR:
8242 case NBACKGND:
8243 case NSUBSHELL:
8244 new->nredir.redirect = copynode(n->nredir.redirect);
8245 new->nredir.n = copynode(n->nredir.n);
8246 break;
8247 case NAND:
8248 case NOR:
8249 case NSEMI:
8250 case NWHILE:
8251 case NUNTIL:
8252 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8253 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8254 break;
8255 case NIF:
8256 new->nif.elsepart = copynode(n->nif.elsepart);
8257 new->nif.ifpart = copynode(n->nif.ifpart);
8258 new->nif.test = copynode(n->nif.test);
8259 break;
8260 case NFOR:
8261 new->nfor.var = nodeckstrdup(n->nfor.var);
8262 new->nfor.body = copynode(n->nfor.body);
8263 new->nfor.args = copynode(n->nfor.args);
8264 break;
8265 case NCASE:
8266 new->ncase.cases = copynode(n->ncase.cases);
8267 new->ncase.expr = copynode(n->ncase.expr);
8268 break;
8269 case NCLIST:
8270 new->nclist.body = copynode(n->nclist.body);
8271 new->nclist.pattern = copynode(n->nclist.pattern);
8272 new->nclist.next = copynode(n->nclist.next);
8273 break;
8274 case NDEFUN:
8275 case NARG:
8276 new->narg.backquote = copynodelist(n->narg.backquote);
8277 new->narg.text = nodeckstrdup(n->narg.text);
8278 new->narg.next = copynode(n->narg.next);
8279 break;
8280 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008281#if ENABLE_ASH_BASH_COMPAT
8282 case NTO2:
8283#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008284 case NCLOBBER:
8285 case NFROM:
8286 case NFROMTO:
8287 case NAPPEND:
8288 new->nfile.fname = copynode(n->nfile.fname);
8289 new->nfile.fd = n->nfile.fd;
8290 new->nfile.next = copynode(n->nfile.next);
8291 break;
8292 case NTOFD:
8293 case NFROMFD:
8294 new->ndup.vname = copynode(n->ndup.vname);
8295 new->ndup.dupfd = n->ndup.dupfd;
8296 new->ndup.fd = n->ndup.fd;
8297 new->ndup.next = copynode(n->ndup.next);
8298 break;
8299 case NHERE:
8300 case NXHERE:
8301 new->nhere.doc = copynode(n->nhere.doc);
8302 new->nhere.fd = n->nhere.fd;
8303 new->nhere.next = copynode(n->nhere.next);
8304 break;
8305 case NNOT:
8306 new->nnot.com = copynode(n->nnot.com);
8307 break;
8308 };
8309 new->type = n->type;
8310 return new;
8311}
8312
8313/*
8314 * Make a copy of a parse tree.
8315 */
8316static struct funcnode *
8317copyfunc(union node *n)
8318{
8319 struct funcnode *f;
8320 size_t blocksize;
8321
8322 funcblocksize = offsetof(struct funcnode, n);
8323 funcstringsize = 0;
8324 calcsize(n);
8325 blocksize = funcblocksize;
8326 f = ckmalloc(blocksize + funcstringsize);
8327 funcblock = (char *) f + offsetof(struct funcnode, n);
8328 funcstring = (char *) f + blocksize;
8329 copynode(n);
8330 f->count = 0;
8331 return f;
8332}
8333
8334/*
8335 * Define a shell function.
8336 */
8337static void
8338defun(char *name, union node *func)
8339{
8340 struct cmdentry entry;
8341
8342 INT_OFF;
8343 entry.cmdtype = CMDFUNCTION;
8344 entry.u.func = copyfunc(func);
8345 addcmdentry(name, &entry);
8346 INT_ON;
8347}
8348
Denis Vlasenko4b875702009-03-19 13:30:04 +00008349/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008350#define SKIPBREAK (1 << 0)
8351#define SKIPCONT (1 << 1)
8352#define SKIPFUNC (1 << 2)
8353#define SKIPFILE (1 << 3)
8354#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008355static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008356static int skipcount; /* number of levels to skip */
8357static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008358static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008359
Denis Vlasenko4b875702009-03-19 13:30:04 +00008360/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008361static int evalstring(char *s, int mask);
8362
Denis Vlasenko4b875702009-03-19 13:30:04 +00008363/* Called to execute a trap.
8364 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008365 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008366 *
8367 * Perhaps we should avoid entering new trap handlers
8368 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008369 */
8370static int
8371dotrap(void)
8372{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008373 uint8_t *g;
8374 int sig;
8375 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008376
8377 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008378 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008379 xbarrier();
8380
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008381 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008382 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denis Vlasenko4b875702009-03-19 13:30:04 +00008383 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008384
Denis Vlasenko4b875702009-03-19 13:30:04 +00008385 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008386 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008387 t = trap[sig];
8388 /* non-trapped SIGINT is handled separately by raise_interrupt,
8389 * don't upset it by resetting gotsig[SIGINT-1] */
8390 if (sig == SIGINT && !t)
8391 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008392
8393 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008394 *g = 0;
8395 if (!t)
8396 continue;
Denys Vlasenko928e2a72016-09-29 00:30:31 +02008397 evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008398 exitstatus = savestatus;
Denys Vlasenko928e2a72016-09-29 00:30:31 +02008399 if (evalskip) {
8400 TRACE(("dotrap returns %d\n", evalskip));
8401 return evalskip;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008402 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008403 }
8404
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008405 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008406 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008407}
8408
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008409/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008410static int evalloop(union node *, int);
8411static int evalfor(union node *, int);
8412static int evalcase(union node *, int);
8413static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008414static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008415static int evalpipe(union node *, int);
8416static int evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008417static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008418static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008419
Eric Andersen62483552001-07-10 06:09:16 +00008420/*
Eric Andersenc470f442003-07-28 09:56:35 +00008421 * Evaluate a parse tree. The value is left in the global variable
8422 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008423 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008424static int
Eric Andersenc470f442003-07-28 09:56:35 +00008425evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008426{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008427 struct jmploc *volatile savehandler = exception_handler;
8428 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008429 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008430 int (*evalfn)(union node *, int);
8431 int status = 0;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008432 int int_level;
8433
8434 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008435
Eric Andersenc470f442003-07-28 09:56:35 +00008436 if (n == NULL) {
8437 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008438 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008439 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008440 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008441
8442 exception_handler = &jmploc;
8443 {
8444 int err = setjmp(jmploc.loc);
8445 if (err) {
8446 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008447 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008448 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8449 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008450 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008451 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008452 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008453 TRACE(("exception %d in evaltree, propagating err=%d\n",
8454 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008455 exception_handler = savehandler;
8456 longjmp(exception_handler->loc, err);
8457 }
8458 }
8459
Eric Andersenc470f442003-07-28 09:56:35 +00008460 switch (n->type) {
8461 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008462#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008463 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008464 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008465 break;
8466#endif
8467 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008468 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008469 goto setstatus;
8470 case NREDIR:
8471 expredir(n->nredir.redirect);
8472 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8473 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008474 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008475 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008476 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008477 goto setstatus;
8478 case NCMD:
8479 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008480 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008481 if (eflag && !(flags & EV_TESTED))
8482 checkexit = ~0;
8483 goto calleval;
8484 case NFOR:
8485 evalfn = evalfor;
8486 goto calleval;
8487 case NWHILE:
8488 case NUNTIL:
8489 evalfn = evalloop;
8490 goto calleval;
8491 case NSUBSHELL:
Rostislav Skudnov204c7fb2016-09-16 19:04:02 +00008492 evalfn = evalsubshell;
8493 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008494 case NBACKGND:
8495 evalfn = evalsubshell;
8496 goto calleval;
8497 case NPIPE:
8498 evalfn = evalpipe;
8499 goto checkexit;
8500 case NCASE:
8501 evalfn = evalcase;
8502 goto calleval;
8503 case NAND:
8504 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008505 case NSEMI: {
8506
Eric Andersenc470f442003-07-28 09:56:35 +00008507#if NAND + 1 != NOR
8508#error NAND + 1 != NOR
8509#endif
8510#if NOR + 1 != NSEMI
8511#error NOR + 1 != NSEMI
8512#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008513 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008514 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008515 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008516 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008517 );
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008518 if (!status == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008519 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008520 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008521 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008522 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008523 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008524 status = evalfn(n, flags);
8525 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008526 }
Eric Andersenc470f442003-07-28 09:56:35 +00008527 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008528 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008529 if (evalskip)
8530 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008531 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008532 n = n->nif.ifpart;
8533 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008534 }
8535 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008536 n = n->nif.elsepart;
8537 goto evaln;
8538 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008539 status = 0;
8540 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008541 case NDEFUN:
8542 defun(n->narg.text, n->narg.next);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008543 /* Not necessary. To test it:
8544 * "false; f() { qwerty; }; echo $?" should print 0.
8545 */
8546 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008547 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008548 exitstatus = status;
8549 break;
8550 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008551
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008552 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008553 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008554
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008555 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008556 /* Order of checks below is important:
8557 * signal handlers trigger before exit caused by "set -e".
8558 */
8559 if (pending_sig && dotrap())
8560 goto exexit;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008561 if (checkexit & status)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008562 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008563
8564 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008565 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008566 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008567 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008568
8569 RESTORE_INT(int_level);
8570 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008571
8572 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008573}
8574
Eric Andersenc470f442003-07-28 09:56:35 +00008575#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8576static
8577#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008578int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008579
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008580static int
Eric Andersenc470f442003-07-28 09:56:35 +00008581evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008582{
8583 int status;
8584
8585 loopnest++;
8586 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008587 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008588 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008589 int i;
8590
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008591 i = evaltree(n->nbinary.ch1, EV_TESTED);
Eric Andersencb57d552001-06-28 07:25:16 +00008592 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008593 skipping:
8594 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008595 evalskip = 0;
8596 continue;
8597 }
8598 if (evalskip == SKIPBREAK && --skipcount <= 0)
8599 evalskip = 0;
8600 break;
8601 }
Eric Andersenc470f442003-07-28 09:56:35 +00008602 if (n->type != NWHILE)
8603 i = !i;
8604 if (i != 0)
8605 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008606 status = evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008607 if (evalskip)
8608 goto skipping;
8609 }
Eric Andersencb57d552001-06-28 07:25:16 +00008610 exitstatus = status;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008611 loopnest--;
8612
8613 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008614}
8615
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008616static int
Eric Andersenc470f442003-07-28 09:56:35 +00008617evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008618{
8619 struct arglist arglist;
8620 union node *argp;
8621 struct strlist *sp;
8622 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008623 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008624
8625 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008626 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008627 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008628 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008629 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008630 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008631 if (evalskip)
8632 goto out;
8633 }
8634 *arglist.lastp = NULL;
8635
Eric Andersencb57d552001-06-28 07:25:16 +00008636 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008637 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008638 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008639 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008640 status = evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008641 if (evalskip) {
8642 if (evalskip == SKIPCONT && --skipcount <= 0) {
8643 evalskip = 0;
8644 continue;
8645 }
8646 if (evalskip == SKIPBREAK && --skipcount <= 0)
8647 evalskip = 0;
8648 break;
8649 }
8650 }
8651 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008652 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008653 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008654
8655 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008656}
8657
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008658static int
Eric Andersenc470f442003-07-28 09:56:35 +00008659evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008660{
8661 union node *cp;
8662 union node *patp;
8663 struct arglist arglist;
8664 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008665 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008666
8667 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008668 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008669 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008670 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008671 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8672 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008673 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008674 /* Ensure body is non-empty as otherwise
8675 * EV_EXIT may prevent us from setting the
8676 * exit status.
8677 */
8678 if (evalskip == 0 && cp->nclist.body) {
8679 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008680 }
8681 goto out;
8682 }
8683 }
8684 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008685 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008686 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008687
8688 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008689}
8690
Eric Andersenc470f442003-07-28 09:56:35 +00008691/*
8692 * Kick off a subshell to evaluate a tree.
8693 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008694static int
Eric Andersenc470f442003-07-28 09:56:35 +00008695evalsubshell(union node *n, int flags)
8696{
8697 struct job *jp;
8698 int backgnd = (n->type == NBACKGND);
8699 int status;
8700
8701 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008702 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008703 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008704 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008705 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008706 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008707 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008708 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008709 flags |= EV_EXIT;
8710 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008711 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008712 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008713 redirect(n->nredir.redirect, 0);
8714 evaltreenr(n->nredir.n, flags);
8715 /* never returns */
8716 }
8717 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008718 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008719 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008720 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008721 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008722}
8723
Eric Andersenc470f442003-07-28 09:56:35 +00008724/*
8725 * Compute the names of the files in a redirection list.
8726 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008727static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008728static void
8729expredir(union node *n)
8730{
8731 union node *redir;
8732
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008733 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008734 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008735
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008736 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008737 fn.lastp = &fn.list;
8738 switch (redir->type) {
8739 case NFROMTO:
8740 case NFROM:
8741 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008742#if ENABLE_ASH_BASH_COMPAT
8743 case NTO2:
8744#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008745 case NCLOBBER:
8746 case NAPPEND:
8747 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008748 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008749#if ENABLE_ASH_BASH_COMPAT
8750 store_expfname:
8751#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008752#if 0
8753// By the design of stack allocator, the loop of this kind:
8754// while true; do while true; do break; done </dev/null; done
8755// will look like a memory leak: ash plans to free expfname's
8756// of "/dev/null" as soon as it finishes running the loop
8757// (in this case, never).
8758// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008759 if (redir->nfile.expfname)
8760 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008761// It results in corrupted state of stacked allocations.
8762#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008763 redir->nfile.expfname = fn.list->text;
8764 break;
8765 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008766 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008767 if (redir->ndup.vname) {
8768 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008769 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008770 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008771#if ENABLE_ASH_BASH_COMPAT
8772//FIXME: we used expandarg with different args!
8773 if (!isdigit_str9(fn.list->text)) {
8774 /* >&file, not >&fd */
8775 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8776 ash_msg_and_raise_error("redir error");
8777 redir->type = NTO2;
8778 goto store_expfname;
8779 }
8780#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008781 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008782 }
8783 break;
8784 }
8785 }
8786}
8787
Eric Andersencb57d552001-06-28 07:25:16 +00008788/*
Eric Andersencb57d552001-06-28 07:25:16 +00008789 * Evaluate a pipeline. All the processes in the pipeline are children
8790 * of the process creating the pipeline. (This differs from some versions
8791 * of the shell, which make the last process in a pipeline the parent
8792 * of all the rest.)
8793 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008794static int
Eric Andersenc470f442003-07-28 09:56:35 +00008795evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008796{
8797 struct job *jp;
8798 struct nodelist *lp;
8799 int pipelen;
8800 int prevfd;
8801 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008802 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008803
Eric Andersenc470f442003-07-28 09:56:35 +00008804 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008805 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008806 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008807 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008808 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008809 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008810 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008811 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008812 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008813 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008814 pip[1] = -1;
8815 if (lp->next) {
8816 if (pipe(pip) < 0) {
8817 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008818 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008819 }
8820 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008821 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008822 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008823 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008824 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008825 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008826 if (prevfd > 0) {
8827 dup2(prevfd, 0);
8828 close(prevfd);
8829 }
8830 if (pip[1] > 1) {
8831 dup2(pip[1], 1);
8832 close(pip[1]);
8833 }
Eric Andersenc470f442003-07-28 09:56:35 +00008834 evaltreenr(lp->n, flags);
8835 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008836 }
8837 if (prevfd >= 0)
8838 close(prevfd);
8839 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008840 /* Don't want to trigger debugging */
8841 if (pip[1] != -1)
8842 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008843 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008844 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008845 status = waitforjob(jp);
8846 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008847 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008848 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008849
8850 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008851}
8852
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008853/*
8854 * Controls whether the shell is interactive or not.
8855 */
8856static void
8857setinteractive(int on)
8858{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008859 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008860
8861 if (++on == is_interactive)
8862 return;
8863 is_interactive = on;
8864 setsignal(SIGINT);
8865 setsignal(SIGQUIT);
8866 setsignal(SIGTERM);
8867#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8868 if (is_interactive > 1) {
8869 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008870 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008871
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008872 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008873 /* note: ash and hush share this string */
8874 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008875 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8876 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008877 bb_banner,
8878 "built-in shell (ash)"
8879 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008880 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008881 }
8882 }
8883#endif
8884}
8885
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008886static void
8887optschanged(void)
8888{
8889#if DEBUG
8890 opentrace();
8891#endif
8892 setinteractive(iflag);
8893 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008894#if ENABLE_FEATURE_EDITING_VI
8895 if (viflag)
8896 line_input_state->flags |= VI_MODE;
8897 else
8898 line_input_state->flags &= ~VI_MODE;
8899#else
8900 viflag = 0; /* forcibly keep the option off */
8901#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008902}
8903
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008904static struct localvar *localvars;
8905
8906/*
8907 * Called after a function returns.
8908 * Interrupts must be off.
8909 */
8910static void
8911poplocalvars(void)
8912{
8913 struct localvar *lvp;
8914 struct var *vp;
8915
8916 while ((lvp = localvars) != NULL) {
8917 localvars = lvp->next;
8918 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008919 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008920 if (vp == NULL) { /* $- saved */
8921 memcpy(optlist, lvp->text, sizeof(optlist));
8922 free((char*)lvp->text);
8923 optschanged();
8924 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008925 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008926 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008927 if (vp->var_func)
8928 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008929 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008930 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008931 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008932 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008933 }
8934 free(lvp);
8935 }
8936}
8937
8938static int
8939evalfun(struct funcnode *func, int argc, char **argv, int flags)
8940{
8941 volatile struct shparam saveparam;
8942 struct localvar *volatile savelocalvars;
8943 struct jmploc *volatile savehandler;
8944 struct jmploc jmploc;
8945 int e;
8946
8947 saveparam = shellparam;
8948 savelocalvars = localvars;
8949 e = setjmp(jmploc.loc);
8950 if (e) {
8951 goto funcdone;
8952 }
8953 INT_OFF;
8954 savehandler = exception_handler;
8955 exception_handler = &jmploc;
8956 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008957 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008958 func->count++;
8959 funcnest++;
8960 INT_ON;
8961 shellparam.nparam = argc - 1;
8962 shellparam.p = argv + 1;
8963#if ENABLE_ASH_GETOPTS
8964 shellparam.optind = 1;
8965 shellparam.optoff = -1;
8966#endif
8967 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008968 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008969 INT_OFF;
8970 funcnest--;
8971 freefunc(func);
8972 poplocalvars();
8973 localvars = savelocalvars;
8974 freeparam(&shellparam);
8975 shellparam = saveparam;
8976 exception_handler = savehandler;
8977 INT_ON;
8978 evalskip &= ~SKIPFUNC;
8979 return e;
8980}
8981
Denis Vlasenko131ae172007-02-18 13:00:19 +00008982#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008983static char **
8984parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008985{
8986 char *cp, c;
8987
8988 for (;;) {
8989 cp = *++argv;
8990 if (!cp)
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008991 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008992 if (*cp++ != '-')
8993 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008994 c = *cp++;
8995 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008996 break;
8997 if (c == '-' && !*cp) {
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008998 if (!*++argv)
8999 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009000 break;
9001 }
9002 do {
9003 switch (c) {
9004 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00009005 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00009006 break;
9007 default:
9008 /* run 'typecmd' for other options */
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01009009 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009010 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00009011 c = *cp++;
9012 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00009013 }
9014 return argv;
9015}
9016#endif
9017
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009018/*
9019 * Make a variable a local variable. When a variable is made local, it's
9020 * value and flags are saved in a localvar structure. The saved values
9021 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009022 * "-" as a special case: it makes changes to "set +-options" local
9023 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009024 */
9025static void
9026mklocal(char *name)
9027{
9028 struct localvar *lvp;
9029 struct var **vpp;
9030 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009031 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009032
9033 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009034 /* Cater for duplicate "local". Examples:
9035 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9036 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9037 */
9038 lvp = localvars;
9039 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009040 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009041 if (eq)
9042 setvareq(name, 0);
9043 /* else:
9044 * it's a duplicate "local VAR" declaration, do nothing
9045 */
9046 return;
9047 }
9048 lvp = lvp->next;
9049 }
9050
9051 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009052 if (LONE_DASH(name)) {
9053 char *p;
9054 p = ckmalloc(sizeof(optlist));
9055 lvp->text = memcpy(p, optlist, sizeof(optlist));
9056 vp = NULL;
9057 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009058 vpp = hashvar(name);
9059 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009060 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009061 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009062 if (eq)
9063 setvareq(name, VSTRFIXED);
9064 else
9065 setvar(name, NULL, VSTRFIXED);
9066 vp = *vpp; /* the new variable */
9067 lvp->flags = VUNSET;
9068 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009069 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009070 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009071 /* make sure neither "struct var" nor string gets freed
9072 * during (un)setting:
9073 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009074 vp->flags |= VSTRFIXED|VTEXTFIXED;
9075 if (eq)
9076 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009077 else
9078 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009079 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009080 }
9081 }
9082 lvp->vp = vp;
9083 lvp->next = localvars;
9084 localvars = lvp;
9085 INT_ON;
9086}
9087
9088/*
9089 * The "local" command.
9090 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009091static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009092localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009093{
9094 char *name;
9095
Ron Yorstonef2386b2015-10-29 16:19:14 +00009096 if (!funcnest)
9097 ash_msg_and_raise_error("not in a function");
9098
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009099 argv = argptr;
9100 while ((name = *argv++) != NULL) {
9101 mklocal(name);
9102 }
9103 return 0;
9104}
9105
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009106static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009107falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009108{
9109 return 1;
9110}
9111
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009112static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009113truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009114{
9115 return 0;
9116}
9117
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009118static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009119execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009120{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009121 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009122 iflag = 0; /* exit on error */
9123 mflag = 0;
9124 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009125 /* We should set up signals for "exec CMD"
9126 * the same way as for "CMD" without "exec".
9127 * But optschanged->setinteractive->setsignal
9128 * still thought we are a root shell. Therefore, for example,
9129 * SIGQUIT is still set to IGN. Fix it:
9130 */
9131 shlvl++;
9132 setsignal(SIGQUIT);
9133 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9134 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9135 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9136
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009137 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009138 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009139 }
9140 return 0;
9141}
9142
9143/*
9144 * The return command.
9145 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009146static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009147returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009148{
9149 /*
9150 * If called outside a function, do what ksh does;
9151 * skip the rest of the file.
9152 */
9153 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9154 return argv[1] ? number(argv[1]) : exitstatus;
9155}
9156
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009157/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009158static int breakcmd(int, char **) FAST_FUNC;
9159static int dotcmd(int, char **) FAST_FUNC;
9160static int evalcmd(int, char **) FAST_FUNC;
9161static int exitcmd(int, char **) FAST_FUNC;
9162static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009163#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009164static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009165#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009166#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009167static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009168#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009169#if MAX_HISTORY
9170static int historycmd(int, char **) FAST_FUNC;
9171#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009172#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009173static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009174#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009175static int readcmd(int, char **) FAST_FUNC;
9176static int setcmd(int, char **) FAST_FUNC;
9177static int shiftcmd(int, char **) FAST_FUNC;
9178static int timescmd(int, char **) FAST_FUNC;
9179static int trapcmd(int, char **) FAST_FUNC;
9180static int umaskcmd(int, char **) FAST_FUNC;
9181static int unsetcmd(int, char **) FAST_FUNC;
9182static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009183
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009184#define BUILTIN_NOSPEC "0"
9185#define BUILTIN_SPECIAL "1"
9186#define BUILTIN_REGULAR "2"
9187#define BUILTIN_SPEC_REG "3"
9188#define BUILTIN_ASSIGN "4"
9189#define BUILTIN_SPEC_ASSG "5"
9190#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009191#define BUILTIN_SPEC_REG_ASSG "7"
9192
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009193/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009194#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009195static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009196#endif
9197#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009198static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009199#endif
9200#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009201static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009202#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009203
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009204/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009205static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009206 { BUILTIN_SPEC_REG "." , dotcmd },
9207 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009208#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009209 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009210#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009211 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009212#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009213#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009214#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009215 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009216#endif
9217#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009218 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009219#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009220 { BUILTIN_SPEC_REG "break" , breakcmd },
9221 { BUILTIN_REGULAR "cd" , cdcmd },
9222 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009223#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009224 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009225#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009226 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009227#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009228 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009229#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009230 { BUILTIN_SPEC_REG "eval" , evalcmd },
9231 { BUILTIN_SPEC_REG "exec" , execcmd },
9232 { BUILTIN_SPEC_REG "exit" , exitcmd },
9233 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9234 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009235#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009236 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009237#endif
9238#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009239 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009240#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009241 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009242#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009243 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009244#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009245#if MAX_HISTORY
9246 { BUILTIN_NOSPEC "history" , historycmd },
9247#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009248#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009249 { BUILTIN_REGULAR "jobs" , jobscmd },
9250 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009251#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009252#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009253 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009254#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009255 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009256#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009257 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009258#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009259 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9260 { BUILTIN_REGULAR "read" , readcmd },
9261 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9262 { BUILTIN_SPEC_REG "return" , returncmd },
9263 { BUILTIN_SPEC_REG "set" , setcmd },
9264 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009265#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009266 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009267#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009268#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009269 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009270#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009271 { BUILTIN_SPEC_REG "times" , timescmd },
9272 { BUILTIN_SPEC_REG "trap" , trapcmd },
9273 { BUILTIN_REGULAR "true" , truecmd },
9274 { BUILTIN_NOSPEC "type" , typecmd },
9275 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9276 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009277#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009278 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009279#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009280 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9281 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009282};
9283
Denis Vlasenko80591b02008-03-25 07:49:43 +00009284/* Should match the above table! */
9285#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009286 /* . : */ 2 + \
9287 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9288 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9289 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9290 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9291 /* break cd cddir */ 3)
9292#define EVALCMD (COMMANDCMD + \
9293 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9294 /* continue */ 1 + \
9295 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9296 0)
9297#define EXECCMD (EVALCMD + \
9298 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009299
9300/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009301 * Search the table of builtin commands.
9302 */
9303static struct builtincmd *
9304find_builtin(const char *name)
9305{
9306 struct builtincmd *bp;
9307
9308 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009309 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009310 pstrcmp
9311 );
9312 return bp;
9313}
9314
9315/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009316 * Execute a simple command.
9317 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009318static int
9319isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009320{
9321 const char *q = endofname(p);
9322 if (p == q)
9323 return 0;
9324 return *q == '=';
9325}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009326static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009327bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009328{
9329 /* Preserve exitstatus of a previous possible redirection
9330 * as POSIX mandates */
9331 return back_exitstatus;
9332}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009333static int
Eric Andersenc470f442003-07-28 09:56:35 +00009334evalcommand(union node *cmd, int flags)
9335{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009336 static const struct builtincmd null_bltin = {
9337 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009338 };
Eric Andersenc470f442003-07-28 09:56:35 +00009339 struct stackmark smark;
9340 union node *argp;
9341 struct arglist arglist;
9342 struct arglist varlist;
9343 char **argv;
9344 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009345 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009346 struct cmdentry cmdentry;
9347 struct job *jp;
9348 char *lastarg;
9349 const char *path;
9350 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009351 int status;
9352 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009353 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009354 smallint cmd_is_exec;
9355 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009356
9357 /* First expand the arguments. */
9358 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9359 setstackmark(&smark);
9360 back_exitstatus = 0;
9361
9362 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009363 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009364 varlist.lastp = &varlist.list;
9365 *varlist.lastp = NULL;
9366 arglist.lastp = &arglist.list;
9367 *arglist.lastp = NULL;
9368
9369 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009370 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009371 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9372 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9373 }
9374
Eric Andersenc470f442003-07-28 09:56:35 +00009375 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9376 struct strlist **spp;
9377
9378 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009379 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009380 expandarg(argp, &arglist, EXP_VARTILDE);
9381 else
9382 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9383
Eric Andersenc470f442003-07-28 09:56:35 +00009384 for (sp = *spp; sp; sp = sp->next)
9385 argc++;
9386 }
9387
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009388 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009389 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009390 TRACE(("evalcommand arg: %s\n", sp->text));
9391 *nargv++ = sp->text;
9392 }
9393 *nargv = NULL;
9394
9395 lastarg = NULL;
9396 if (iflag && funcnest == 0 && argc > 0)
9397 lastarg = nargv[-1];
9398
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009399 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009400 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009401 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009402
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009403 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009404 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9405 struct strlist **spp;
9406 char *p;
9407
9408 spp = varlist.lastp;
9409 expandarg(argp, &varlist, EXP_VARTILDE);
9410
9411 /*
9412 * Modify the command lookup path, if a PATH= assignment
9413 * is present
9414 */
9415 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009416 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009417 path = p;
9418 }
9419
9420 /* Print the command if xflag is set. */
9421 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009422 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009423 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009424
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009425 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009426 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009427 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009428 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009429 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009430 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009431 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009432 }
9433 sp = arglist.list;
9434 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009435 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009436 }
9437
9438 cmd_is_exec = 0;
9439 spclbltin = -1;
9440
9441 /* Now locate the command. */
9442 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009443 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009444#if ENABLE_ASH_CMDCMD
9445 const char *oldpath = path + 5;
9446#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009447 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009448 for (;;) {
9449 find_command(argv[0], &cmdentry, cmd_flag, path);
9450 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009451 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009452 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009453 goto bail;
9454 }
9455
9456 /* implement bltin and command here */
9457 if (cmdentry.cmdtype != CMDBUILTIN)
9458 break;
9459 if (spclbltin < 0)
9460 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9461 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009462 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009463#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009464 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009465 path = oldpath;
9466 nargv = parse_command_args(argv, &path);
9467 if (!nargv)
9468 break;
9469 argc -= nargv - argv;
9470 argv = nargv;
9471 cmd_flag |= DO_NOFUNC;
9472 } else
9473#endif
9474 break;
9475 }
9476 }
9477
9478 if (status) {
9479 /* We have a redirection error. */
9480 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009481 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009482 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009483 exitstatus = status;
9484 goto out;
9485 }
9486
9487 /* Execute the command. */
9488 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009489 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009490
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009491#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009492/* (1) BUG: if variables are set, we need to fork, or save/restore them
9493 * around run_nofork_applet() call.
9494 * (2) Should this check also be done in forkshell()?
9495 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9496 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009497 /* find_command() encodes applet_no as (-2 - applet_no) */
9498 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009499 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009500 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009501 /* run <applet>_main() */
9502 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009503 break;
9504 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009505#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009506 /* Can we avoid forking off? For example, very last command
9507 * in a script or a subshell does not need forking,
9508 * we can just exec it.
9509 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009510 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009511 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009512 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009513 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009514 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009515 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009516 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009517 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009518 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009519 break;
9520 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009521 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009522 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009523 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009524 }
9525 listsetvar(varlist.list, VEXPORT|VSTACK);
9526 shellexec(argv, path, cmdentry.u.index);
9527 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009528 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009529 case CMDBUILTIN:
9530 cmdenviron = varlist.list;
9531 if (cmdenviron) {
9532 struct strlist *list = cmdenviron;
9533 int i = VNOSET;
9534 if (spclbltin > 0 || argc == 0) {
9535 i = 0;
9536 if (cmd_is_exec && argc > 1)
9537 i = VEXPORT;
9538 }
9539 listsetvar(list, i);
9540 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009541 /* Tight loop with builtins only:
9542 * "while kill -0 $child; do true; done"
9543 * will never exit even if $child died, unless we do this
9544 * to reap the zombie and make kill detect that it's gone: */
9545 dowait(DOWAIT_NONBLOCK, NULL);
9546
Eric Andersenc470f442003-07-28 09:56:35 +00009547 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9548 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009549 int i = exception_type;
Ron Yorston8c55dc72015-10-30 19:06:47 +00009550 if (i == EXEXIT || i == EXEXEC)
Eric Andersenc470f442003-07-28 09:56:35 +00009551 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009552 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009553 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009554 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009555 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009556 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009557 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009558 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009559 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009560 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009561 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009562 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009563 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009564 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009565
9566 case CMDFUNCTION:
9567 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009568 /* See above for the rationale */
9569 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009570 if (evalfun(cmdentry.u.func, argc, argv, flags))
9571 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009572 readstatus:
9573 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009574 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009575 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009576
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009577 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009578 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009579 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009580 /* dsl: I think this is intended to be used to support
9581 * '_' in 'vi' command mode during line editing...
9582 * However I implemented that within libedit itself.
9583 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009584 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009585 }
Eric Andersenc470f442003-07-28 09:56:35 +00009586 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009587
9588 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009589}
9590
9591static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009592evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9593{
Eric Andersenc470f442003-07-28 09:56:35 +00009594 char *volatile savecmdname;
9595 struct jmploc *volatile savehandler;
9596 struct jmploc jmploc;
9597 int i;
9598
9599 savecmdname = commandname;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009600 i = setjmp(jmploc.loc);
9601 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009602 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009603 savehandler = exception_handler;
9604 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009605 commandname = argv[0];
9606 argptr = argv + 1;
9607 optptr = NULL; /* initialize nextopt */
9608 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009609 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009610 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009611 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009612 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009613 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009614 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009615
9616 return i;
9617}
9618
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009619static int
9620goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009621{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009622 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009623}
9624
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009625
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009626/*
9627 * Search for a command. This is called before we fork so that the
9628 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009629 * the child. The check for "goodname" is an overly conservative
9630 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009631 */
Eric Andersenc470f442003-07-28 09:56:35 +00009632static void
9633prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009634{
9635 struct cmdentry entry;
9636
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009637 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9638 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009639}
9640
Eric Andersencb57d552001-06-28 07:25:16 +00009641
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009642/* ============ Builtin commands
9643 *
9644 * Builtin commands whose functions are closely tied to evaluation
9645 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009646 */
9647
9648/*
Eric Andersencb57d552001-06-28 07:25:16 +00009649 * Handle break and continue commands. Break, continue, and return are
9650 * all handled by setting the evalskip flag. The evaluation routines
9651 * above all check this flag, and if it is set they start skipping
9652 * commands rather than executing them. The variable skipcount is
9653 * the number of loops to break/continue, or the number of function
9654 * levels to return. (The latter is always 1.) It should probably
9655 * be an error to break out of more loops than exist, but it isn't
9656 * in the standard shell so we don't make it one here.
9657 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009658static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009659breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009660{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009661 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009662
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009663 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009664 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009665 if (n > loopnest)
9666 n = loopnest;
9667 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009668 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009669 skipcount = n;
9670 }
9671 return 0;
9672}
9673
Eric Andersenc470f442003-07-28 09:56:35 +00009674
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009675/* ============ input.c
9676 *
Eric Andersen90898442003-08-06 11:20:52 +00009677 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009678 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009679
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009680enum {
9681 INPUT_PUSH_FILE = 1,
9682 INPUT_NOFILE_OK = 2,
9683};
Eric Andersencb57d552001-06-28 07:25:16 +00009684
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009685static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009686/* values of checkkwd variable */
9687#define CHKALIAS 0x1
9688#define CHKKWD 0x2
9689#define CHKNL 0x4
9690
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009691/*
9692 * Push a string back onto the input at this current parsefile level.
9693 * We handle aliases this way.
9694 */
9695#if !ENABLE_ASH_ALIAS
9696#define pushstring(s, ap) pushstring(s)
9697#endif
9698static void
9699pushstring(char *s, struct alias *ap)
9700{
9701 struct strpush *sp;
9702 int len;
9703
9704 len = strlen(s);
9705 INT_OFF;
9706 if (g_parsefile->strpush) {
9707 sp = ckzalloc(sizeof(*sp));
9708 sp->prev = g_parsefile->strpush;
9709 } else {
9710 sp = &(g_parsefile->basestrpush);
9711 }
9712 g_parsefile->strpush = sp;
9713 sp->prev_string = g_parsefile->next_to_pgetc;
9714 sp->prev_left_in_line = g_parsefile->left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009715 sp->unget = g_parsefile->unget;
9716 memcpy(sp->lastc, g_parsefile->lastc, sizeof(sp->lastc));
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009717#if ENABLE_ASH_ALIAS
9718 sp->ap = ap;
9719 if (ap) {
9720 ap->flag |= ALIASINUSE;
9721 sp->string = s;
9722 }
9723#endif
9724 g_parsefile->next_to_pgetc = s;
9725 g_parsefile->left_in_line = len;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009726 g_parsefile->unget = 0;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009727 INT_ON;
9728}
9729
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009730static void
9731popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009732{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009733 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009734
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009735 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009736#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009737 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009738 if (g_parsefile->next_to_pgetc[-1] == ' '
9739 || g_parsefile->next_to_pgetc[-1] == '\t'
9740 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009741 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009742 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009743 if (sp->string != sp->ap->val) {
9744 free(sp->string);
9745 }
9746 sp->ap->flag &= ~ALIASINUSE;
9747 if (sp->ap->flag & ALIASDEAD) {
9748 unalias(sp->ap->name);
9749 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009750 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009751#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009752 g_parsefile->next_to_pgetc = sp->prev_string;
9753 g_parsefile->left_in_line = sp->prev_left_in_line;
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009754 g_parsefile->unget = sp->unget;
9755 memcpy(g_parsefile->lastc, sp->lastc, sizeof(sp->lastc));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009756 g_parsefile->strpush = sp->prev;
9757 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009758 free(sp);
9759 INT_ON;
9760}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009761
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009762static int
9763preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009764{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009765 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009766 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009767
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009768 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009769#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009770 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009771 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009772 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009773 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009774 int timeout = -1;
9775# if ENABLE_ASH_IDLE_TIMEOUT
9776 if (iflag) {
9777 const char *tmout_var = lookupvar("TMOUT");
9778 if (tmout_var) {
9779 timeout = atoi(tmout_var) * 1000;
9780 if (timeout <= 0)
9781 timeout = -1;
9782 }
9783 }
9784# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009785# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009786 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009787# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009788 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009789 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009790 if (nr == 0) {
9791 /* Ctrl+C pressed */
9792 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009793 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009794 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009795 raise(SIGINT);
9796 return 1;
9797 }
Eric Andersenc470f442003-07-28 09:56:35 +00009798 goto retry;
9799 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009800 if (nr < 0) {
9801 if (errno == 0) {
9802 /* Ctrl+D pressed */
9803 nr = 0;
9804 }
9805# if ENABLE_ASH_IDLE_TIMEOUT
9806 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009807 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009808 exitshell();
9809 }
9810# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009811 }
Eric Andersencb57d552001-06-28 07:25:16 +00009812 }
9813#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009814 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009815#endif
9816
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009817#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009818 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009819 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009820 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009821 if (flags >= 0 && (flags & O_NONBLOCK)) {
9822 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009823 if (fcntl(0, F_SETFL, flags) >= 0) {
9824 out2str("sh: turning off NDELAY mode\n");
9825 goto retry;
9826 }
9827 }
9828 }
9829 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009830#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009831 return nr;
9832}
9833
9834/*
9835 * Refill the input buffer and return the next input character:
9836 *
9837 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009838 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9839 * or we are reading from a string so we can't refill the buffer,
9840 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009841 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009842 * 4) Process input up to the next newline, deleting nul characters.
9843 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009844//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9845#define pgetc_debug(...) ((void)0)
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009846static int pgetc(void);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009847static int
Eric Andersenc470f442003-07-28 09:56:35 +00009848preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009849{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009850 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009851 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009852
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009853 if (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009854#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009855 if (g_parsefile->left_in_line == -1
9856 && g_parsefile->strpush->ap
9857 && g_parsefile->next_to_pgetc[-1] != ' '
9858 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009859 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009860 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009861 return PEOA;
9862 }
Eric Andersen2870d962001-07-02 17:27:21 +00009863#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009864 popstring();
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009865 return pgetc();
Eric Andersencb57d552001-06-28 07:25:16 +00009866 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009867 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009868 * "pgetc" needs refilling.
9869 */
9870
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009871 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009872 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009873 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009874 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009875 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009876 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009877 /* even in failure keep left_in_line and next_to_pgetc
9878 * in lock step, for correct multi-layer pungetc.
9879 * left_in_line was decremented before preadbuffer(),
9880 * must inc next_to_pgetc: */
9881 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009882 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009883 }
Eric Andersencb57d552001-06-28 07:25:16 +00009884
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009885 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009886 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009887 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009888 again:
9889 more = preadfd();
9890 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009891 /* don't try reading again */
9892 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009893 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009894 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009895 return PEOF;
9896 }
9897 }
9898
Denis Vlasenko727752d2008-11-28 03:41:47 +00009899 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009900 * Set g_parsefile->left_in_line
9901 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009902 * NUL chars are deleted.
9903 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009904 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009905 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009906 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009907
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009908 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009909
Denis Vlasenko727752d2008-11-28 03:41:47 +00009910 c = *q;
9911 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009912 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009913 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009914 q++;
9915 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009916 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009917 break;
9918 }
Eric Andersencb57d552001-06-28 07:25:16 +00009919 }
9920
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009921 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009922 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9923 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009924 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009925 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009926 }
9927 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009928 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009929
Eric Andersencb57d552001-06-28 07:25:16 +00009930 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009931 char save = *q;
9932 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009933 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009934 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009935 }
9936
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009937 pgetc_debug("preadbuffer at %d:%p'%s'",
9938 g_parsefile->left_in_line,
9939 g_parsefile->next_to_pgetc,
9940 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009941 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009942}
9943
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009944static int
9945pgetc(void)
9946{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009947 int c;
9948
9949 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009950 g_parsefile->left_in_line,
9951 g_parsefile->next_to_pgetc,
9952 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009953 if (g_parsefile->unget)
9954 return g_parsefile->lastc[--g_parsefile->unget];
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009955
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009956 if (--g_parsefile->left_in_line >= 0)
9957 c = (signed char)*g_parsefile->next_to_pgetc++;
9958 else
9959 c = preadbuffer();
9960
9961 g_parsefile->lastc[1] = g_parsefile->lastc[0];
9962 g_parsefile->lastc[0] = c;
9963
9964 return c;
9965}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009966
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009967#if ENABLE_ASH_ALIAS
9968static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009969pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009970{
9971 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009972 do {
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009973 pgetc_debug("pgetc at %d:%p'%s'",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009974 g_parsefile->left_in_line,
9975 g_parsefile->next_to_pgetc,
9976 g_parsefile->next_to_pgetc);
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +02009977 c = pgetc();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009978 } while (c == PEOA);
9979 return c;
9980}
9981#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009982# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009983#endif
9984
9985/*
9986 * Read a line from the script.
9987 */
9988static char *
9989pfgets(char *line, int len)
9990{
9991 char *p = line;
9992 int nleft = len;
9993 int c;
9994
9995 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009996 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009997 if (c == PEOF) {
9998 if (p == line)
9999 return NULL;
10000 break;
10001 }
10002 *p++ = c;
10003 if (c == '\n')
10004 break;
10005 }
10006 *p = '\0';
10007 return line;
10008}
10009
Eric Andersenc470f442003-07-28 09:56:35 +000010010/*
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010011 * Undo a call to pgetc. Only two characters may be pushed back.
Eric Andersenc470f442003-07-28 09:56:35 +000010012 * PEOF may be pushed back.
10013 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010014static void
Eric Andersenc470f442003-07-28 09:56:35 +000010015pungetc(void)
10016{
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010017 g_parsefile->unget++;
Eric Andersencb57d552001-06-28 07:25:16 +000010018}
10019
Denys Vlasenko73c3e072016-09-29 17:17:04 +020010020/* This one eats backslash+newline */
10021static int
10022pgetc_eatbnl(void)
10023{
10024 int c;
10025
10026 while ((c = pgetc()) == '\\') {
10027 if (pgetc() != '\n') {
10028 pungetc();
10029 break;
10030 }
10031
10032 g_parsefile->linno++;
10033 setprompt_if(doprompt, 2);
10034 }
10035
10036 return c;
10037}
10038
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010039/*
10040 * To handle the "." command, a stack of input files is used. Pushfile
10041 * adds a new entry to the stack and popfile restores the previous level.
10042 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010043static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010044pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010045{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010046 struct parsefile *pf;
10047
Denis Vlasenko597906c2008-02-20 16:38:54 +000010048 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010049 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010050 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010051 /*pf->strpush = NULL; - ckzalloc did it */
10052 /*pf->basestrpush.prev = NULL;*/
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020010053 /*pf->unget = 0;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010054 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010055}
10056
10057static void
10058popfile(void)
10059{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010060 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010061
Denis Vlasenkob012b102007-02-19 22:43:01 +000010062 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010063 if (pf->pf_fd >= 0)
10064 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010065 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010066 while (pf->strpush)
10067 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010068 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010069 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010070 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010071}
10072
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010073/*
10074 * Return to top level.
10075 */
10076static void
10077popallfiles(void)
10078{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010079 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010080 popfile();
10081}
10082
10083/*
10084 * Close the file(s) that the shell is reading commands from. Called
10085 * after a fork is done.
10086 */
10087static void
10088closescript(void)
10089{
10090 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010091 if (g_parsefile->pf_fd > 0) {
10092 close(g_parsefile->pf_fd);
10093 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010094 }
10095}
10096
10097/*
10098 * Like setinputfile, but takes an open file descriptor. Call this with
10099 * interrupts off.
10100 */
10101static void
10102setinputfd(int fd, int push)
10103{
Denis Vlasenko96e1b382007-09-30 23:50:48 +000010104 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010105 if (push) {
10106 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010107 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010108 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010109 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010110 if (g_parsefile->buf == NULL)
10111 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010112 g_parsefile->left_in_buffer = 0;
10113 g_parsefile->left_in_line = 0;
10114 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010115}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010116
Eric Andersenc470f442003-07-28 09:56:35 +000010117/*
10118 * Set the input to take input from a file. If push is set, push the
10119 * old input onto the stack first.
10120 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010121static int
10122setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010123{
10124 int fd;
10125 int fd2;
10126
Denis Vlasenkob012b102007-02-19 22:43:01 +000010127 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010128 fd = open(fname, O_RDONLY);
10129 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010130 if (flags & INPUT_NOFILE_OK)
10131 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010132 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010133 }
Eric Andersenc470f442003-07-28 09:56:35 +000010134 if (fd < 10) {
10135 fd2 = copyfd(fd, 10);
10136 close(fd);
10137 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010138 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010139 fd = fd2;
10140 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010141 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010142 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010143 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010144 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010145}
10146
Eric Andersencb57d552001-06-28 07:25:16 +000010147/*
10148 * Like setinputfile, but takes input from a string.
10149 */
Eric Andersenc470f442003-07-28 09:56:35 +000010150static void
10151setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010152{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010153 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010154 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010155 g_parsefile->next_to_pgetc = string;
10156 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010157 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010158 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010159 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010160}
10161
10162
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010163/* ============ mail.c
10164 *
10165 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010166 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010167
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010168#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010169
Denys Vlasenko23841622015-10-09 15:52:03 +020010170/* Hash of mtimes of mailboxes */
10171static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010172/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010173static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010174
Eric Andersencb57d552001-06-28 07:25:16 +000010175/*
Eric Andersenc470f442003-07-28 09:56:35 +000010176 * Print appropriate message(s) if mail has arrived.
10177 * If mail_var_path_changed is set,
10178 * then the value of MAIL has mail_var_path_changed,
10179 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010180 */
Eric Andersenc470f442003-07-28 09:56:35 +000010181static void
10182chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010183{
Eric Andersencb57d552001-06-28 07:25:16 +000010184 const char *mpath;
10185 char *p;
10186 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010187 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010188 struct stackmark smark;
10189 struct stat statb;
10190
Eric Andersencb57d552001-06-28 07:25:16 +000010191 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010192 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010193 new_hash = 0;
10194 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010195 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010196 if (p == NULL)
10197 break;
10198 if (*p == '\0')
10199 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010200 for (q = p; *q; q++)
10201 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010202#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010203 if (q[-1] != '/')
10204 abort();
10205#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010206 q[-1] = '\0'; /* delete trailing '/' */
10207 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010208 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010209 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010210 /* Very simplistic "hash": just a sum of all mtimes */
10211 new_hash += (unsigned)statb.st_mtime;
10212 }
10213 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010214 if (mailtime_hash != 0)
10215 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010216 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010217 }
Eric Andersenc470f442003-07-28 09:56:35 +000010218 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010219 popstackmark(&smark);
10220}
Eric Andersencb57d552001-06-28 07:25:16 +000010221
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010222static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010223changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010224{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010225 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010226}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010227
Denis Vlasenko131ae172007-02-18 13:00:19 +000010228#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010229
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010230
10231/* ============ ??? */
10232
Eric Andersencb57d552001-06-28 07:25:16 +000010233/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010234 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010235 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010236static void
10237setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010238{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010239 char **newparam;
10240 char **ap;
10241 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010242
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010243 for (nparam = 0; argv[nparam]; nparam++)
10244 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010245 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10246 while (*argv) {
10247 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010248 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010249 *ap = NULL;
10250 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010251 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010252 shellparam.nparam = nparam;
10253 shellparam.p = newparam;
10254#if ENABLE_ASH_GETOPTS
10255 shellparam.optind = 1;
10256 shellparam.optoff = -1;
10257#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010258}
10259
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010260/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010261 * Process shell options. The global variable argptr contains a pointer
10262 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010263 *
10264 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10265 * For a non-interactive shell, an error condition encountered
10266 * by a special built-in ... shall cause the shell to write a diagnostic message
10267 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010268 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010269 * ...
10270 * Utility syntax error (option or operand error) Shall exit
10271 * ...
10272 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10273 * we see that bash does not do that (set "finishes" with error code 1 instead,
10274 * and shell continues), and people rely on this behavior!
10275 * Testcase:
10276 * set -o barfoo 2>/dev/null
10277 * echo $?
10278 *
10279 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010280 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010281static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010282plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010283{
10284 int i;
10285
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010286 if (name) {
10287 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010288 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010289 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010290 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010291 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010292 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010293 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010294 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010295 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010296 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010297 if (val) {
10298 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10299 } else {
10300 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10301 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010302 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010303 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010304}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010305static void
10306setoption(int flag, int val)
10307{
10308 int i;
10309
10310 for (i = 0; i < NOPTS; i++) {
10311 if (optletters(i) == flag) {
10312 optlist[i] = val;
10313 return;
10314 }
10315 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010316 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010317 /* NOTREACHED */
10318}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010319static int
Eric Andersenc470f442003-07-28 09:56:35 +000010320options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010321{
10322 char *p;
10323 int val;
10324 int c;
10325
10326 if (cmdline)
10327 minusc = NULL;
10328 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010329 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010330 if (c != '-' && c != '+')
10331 break;
10332 argptr++;
10333 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010334 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010335 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010336 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010337 if (!cmdline) {
10338 /* "-" means turn off -x and -v */
10339 if (p[0] == '\0')
10340 xflag = vflag = 0;
10341 /* "--" means reset params */
10342 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010343 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010344 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010345 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010346 }
Eric Andersencb57d552001-06-28 07:25:16 +000010347 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010348 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010349 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010350 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010351 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010352 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010353 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010354 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010355 /* it already printed err message */
10356 return 1; /* error */
10357 }
Eric Andersencb57d552001-06-28 07:25:16 +000010358 if (*argptr)
10359 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010360 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10361 isloginsh = 1;
10362 /* bash does not accept +-login, we also won't */
10363 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010364 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010365 isloginsh = 1;
10366 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010367 } else {
10368 setoption(c, val);
10369 }
10370 }
10371 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010372 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010373}
10374
Eric Andersencb57d552001-06-28 07:25:16 +000010375/*
Eric Andersencb57d552001-06-28 07:25:16 +000010376 * The shift builtin command.
10377 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010378static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010379shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010380{
10381 int n;
10382 char **ap1, **ap2;
10383
10384 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010385 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010386 n = number(argv[1]);
10387 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010388 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010389 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010390 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010391 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010392 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010393 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010394 }
10395 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010396 while ((*ap2++ = *ap1++) != NULL)
10397 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010398#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010399 shellparam.optind = 1;
10400 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010401#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010402 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010403 return 0;
10404}
10405
Eric Andersencb57d552001-06-28 07:25:16 +000010406/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010407 * POSIX requires that 'set' (but not export or readonly) output the
10408 * variables in lexicographic order - by the locale's collating order (sigh).
10409 * Maybe we could keep them in an ordered balanced binary tree
10410 * instead of hashed lists.
10411 * For now just roll 'em through qsort for printing...
10412 */
10413static int
10414showvars(const char *sep_prefix, int on, int off)
10415{
10416 const char *sep;
10417 char **ep, **epend;
10418
10419 ep = listvars(on, off, &epend);
10420 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10421
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010422 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010423
10424 for (; ep < epend; ep++) {
10425 const char *p;
10426 const char *q;
10427
10428 p = strchrnul(*ep, '=');
10429 q = nullstr;
10430 if (*p)
10431 q = single_quote(++p);
10432 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10433 }
10434 return 0;
10435}
10436
10437/*
Eric Andersencb57d552001-06-28 07:25:16 +000010438 * The set command builtin.
10439 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010440static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010441setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010442{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010443 int retval;
10444
Denis Vlasenko68404f12008-03-17 09:00:54 +000010445 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010446 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010447
Denis Vlasenkob012b102007-02-19 22:43:01 +000010448 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010449 retval = options(/*cmdline:*/ 0);
10450 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010451 optschanged();
10452 if (*argptr != NULL) {
10453 setparam(argptr);
10454 }
Eric Andersencb57d552001-06-28 07:25:16 +000010455 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010456 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010457 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010458}
10459
Denis Vlasenko131ae172007-02-18 13:00:19 +000010460#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010461static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010462change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010463{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010464 uint32_t t;
10465
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010466 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010467 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010468 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010469 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010470 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010471 vrandom.flags &= ~VNOFUNC;
10472 } else {
10473 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010474 t = strtoul(value, NULL, 10);
10475 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010476 }
Eric Andersenef02f822004-03-11 13:34:24 +000010477}
Eric Andersen16767e22004-03-16 05:14:10 +000010478#endif
10479
Denis Vlasenko131ae172007-02-18 13:00:19 +000010480#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010481static int
Eric Andersenc470f442003-07-28 09:56:35 +000010482getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010483{
10484 char *p, *q;
10485 char c = '?';
10486 int done = 0;
10487 int err = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010488 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010489 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010490
Denys Vlasenko9c541002015-10-07 15:44:36 +020010491 sbuf[1] = '\0';
10492
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010493 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010494 return 1;
10495 optnext = optfirst + *param_optind - 1;
10496
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010497 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010498 p = NULL;
10499 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010500 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010501 if (p == NULL || *p == '\0') {
10502 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010503 p = *optnext;
10504 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010505 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010506 p = NULL;
10507 done = 1;
10508 goto out;
10509 }
10510 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010511 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010512 goto atend;
10513 }
10514
10515 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010516 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010517 if (*q == '\0') {
10518 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010519 sbuf[0] = c;
10520 /*sbuf[1] = '\0'; - already is */
10521 err |= setvarsafe("OPTARG", sbuf, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010522 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010523 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010524 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010525 }
10526 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010527 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010528 }
10529 if (*++q == ':')
10530 q++;
10531 }
10532
10533 if (*++q == ':') {
10534 if (*p == '\0' && (p = *optnext) == NULL) {
10535 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010536 sbuf[0] = c;
10537 /*sbuf[1] = '\0'; - already is */
10538 err |= setvarsafe("OPTARG", sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010539 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010540 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010541 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010542 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010543 c = '?';
10544 }
Eric Andersenc470f442003-07-28 09:56:35 +000010545 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010546 }
10547
10548 if (p == *optnext)
10549 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010550 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010551 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010552 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010553 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010554 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010555 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010556 *param_optind = optnext - optfirst + 1;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010557 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC);
10558 sbuf[0] = c;
10559 /*sbuf[1] = '\0'; - already is */
10560 err |= setvarsafe(optvar, sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010561 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010562 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010563 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010564 flush_stdout_stderr();
10565 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010566 }
10567 return done;
10568}
Eric Andersenc470f442003-07-28 09:56:35 +000010569
10570/*
10571 * The getopts builtin. Shellparam.optnext points to the next argument
10572 * to be processed. Shellparam.optptr points to the next character to
10573 * be processed in the current argument. If shellparam.optnext is NULL,
10574 * then it's the first time getopts has been called.
10575 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010576static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010577getoptscmd(int argc, char **argv)
10578{
10579 char **optbase;
10580
10581 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010582 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010583 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010584 optbase = shellparam.p;
10585 if (shellparam.optind > shellparam.nparam + 1) {
10586 shellparam.optind = 1;
10587 shellparam.optoff = -1;
10588 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010589 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010590 optbase = &argv[3];
10591 if (shellparam.optind > argc - 2) {
10592 shellparam.optind = 1;
10593 shellparam.optoff = -1;
10594 }
10595 }
10596
10597 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010598 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010599}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010600#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010601
Eric Andersencb57d552001-06-28 07:25:16 +000010602
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010603/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010604
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010605struct heredoc {
10606 struct heredoc *next; /* next here document in list */
10607 union node *here; /* redirection node */
10608 char *eofmark; /* string indicating end of input */
10609 smallint striptabs; /* if set, strip leading tabs */
10610};
10611
10612static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010613static smallint quoteflag; /* set if (part of) last token was quoted */
10614static token_id_t lasttoken; /* last token read (integer id Txxx) */
10615static struct heredoc *heredoclist; /* list of here documents to read */
10616static char *wordtext; /* text of last word returned by readtoken */
10617static struct nodelist *backquotelist;
10618static union node *redirnode;
10619static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010620
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010621static const char *
10622tokname(char *buf, int tok)
10623{
10624 if (tok < TSEMI)
10625 return tokname_array[tok] + 1;
10626 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10627 return buf;
10628}
10629
10630/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010631 * Called when an unexpected token is read during the parse. The argument
10632 * is the token that is expected, or -1 if more than one type of token can
10633 * occur at this point.
10634 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010635static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010636static void
10637raise_error_unexpected_syntax(int token)
10638{
10639 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010640 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010641 int l;
10642
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010643 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010644 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010645 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010646 raise_error_syntax(msg);
10647 /* NOTREACHED */
10648}
Eric Andersencb57d552001-06-28 07:25:16 +000010649
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010650#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010651
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010652/* parsing is heavily cross-recursive, need these forward decls */
10653static union node *andor(void);
10654static union node *pipeline(void);
10655static union node *parse_command(void);
10656static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010657static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010658static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010659
Eric Andersenc470f442003-07-28 09:56:35 +000010660static union node *
10661list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010662{
10663 union node *n1, *n2, *n3;
10664 int tok;
10665
Eric Andersencb57d552001-06-28 07:25:16 +000010666 n1 = NULL;
10667 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010668 switch (peektoken()) {
10669 case TNL:
10670 if (!(nlflag & 1))
10671 break;
10672 parseheredoc();
10673 return n1;
10674
10675 case TEOF:
10676 if (!n1 && (nlflag & 1))
10677 n1 = NODE_EOF;
10678 parseheredoc();
10679 return n1;
10680 }
10681
10682 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10683 if (nlflag == 2 && tokname_array[peektoken()][0])
10684 return n1;
10685 nlflag |= 2;
10686
Eric Andersencb57d552001-06-28 07:25:16 +000010687 n2 = andor();
10688 tok = readtoken();
10689 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010690 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010691 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010692 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010693 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010694 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010695 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010696 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010697 n2 = n3;
10698 }
10699 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010700 }
10701 }
10702 if (n1 == NULL) {
10703 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010704 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010705 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010706 n3->type = NSEMI;
10707 n3->nbinary.ch1 = n1;
10708 n3->nbinary.ch2 = n2;
10709 n1 = n3;
10710 }
10711 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010712 case TNL:
10713 case TEOF:
10714 tokpushback = 1;
10715 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010716 case TBACKGND:
10717 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010718 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010719 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010720 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010721 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010722 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010723 return n1;
10724 }
10725 }
10726}
10727
Eric Andersenc470f442003-07-28 09:56:35 +000010728static union node *
10729andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010730{
Eric Andersencb57d552001-06-28 07:25:16 +000010731 union node *n1, *n2, *n3;
10732 int t;
10733
Eric Andersencb57d552001-06-28 07:25:16 +000010734 n1 = pipeline();
10735 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010736 t = readtoken();
10737 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010738 t = NAND;
10739 } else if (t == TOR) {
10740 t = NOR;
10741 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010742 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010743 return n1;
10744 }
Eric Andersenc470f442003-07-28 09:56:35 +000010745 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010746 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010747 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010748 n3->type = t;
10749 n3->nbinary.ch1 = n1;
10750 n3->nbinary.ch2 = n2;
10751 n1 = n3;
10752 }
10753}
10754
Eric Andersenc470f442003-07-28 09:56:35 +000010755static union node *
10756pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010757{
Eric Andersencb57d552001-06-28 07:25:16 +000010758 union node *n1, *n2, *pipenode;
10759 struct nodelist *lp, *prev;
10760 int negate;
10761
10762 negate = 0;
10763 TRACE(("pipeline: entered\n"));
10764 if (readtoken() == TNOT) {
10765 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010766 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010767 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010768 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010769 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010770 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010771 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010772 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010773 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010774 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010775 pipenode->npipe.cmdlist = lp;
10776 lp->n = n1;
10777 do {
10778 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010779 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010780 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010781 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010782 prev->next = lp;
10783 } while (readtoken() == TPIPE);
10784 lp->next = NULL;
10785 n1 = pipenode;
10786 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010787 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010788 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010789 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010790 n2->type = NNOT;
10791 n2->nnot.com = n1;
10792 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010793 }
10794 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010795}
10796
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010797static union node *
10798makename(void)
10799{
10800 union node *n;
10801
Denis Vlasenko597906c2008-02-20 16:38:54 +000010802 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010803 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010804 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010805 n->narg.text = wordtext;
10806 n->narg.backquote = backquotelist;
10807 return n;
10808}
10809
10810static void
10811fixredir(union node *n, const char *text, int err)
10812{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010813 int fd;
10814
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010815 TRACE(("Fix redir %s %d\n", text, err));
10816 if (!err)
10817 n->ndup.vname = NULL;
10818
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010819 fd = bb_strtou(text, NULL, 10);
10820 if (!errno && fd >= 0)
10821 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010822 else if (LONE_DASH(text))
10823 n->ndup.dupfd = -1;
10824 else {
10825 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010826 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010827 n->ndup.vname = makename();
10828 }
10829}
10830
10831/*
10832 * Returns true if the text contains nothing to expand (no dollar signs
10833 * or backquotes).
10834 */
10835static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010836noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010837{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010838 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010839
Denys Vlasenkocd716832009-11-28 22:14:02 +010010840 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010841 if (c == CTLQUOTEMARK)
10842 continue;
10843 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010844 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010845 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010846 return 0;
10847 }
10848 return 1;
10849}
10850
10851static void
10852parsefname(void)
10853{
10854 union node *n = redirnode;
10855
10856 if (readtoken() != TWORD)
10857 raise_error_unexpected_syntax(-1);
10858 if (n->type == NHERE) {
10859 struct heredoc *here = heredoc;
10860 struct heredoc *p;
10861 int i;
10862
10863 if (quoteflag == 0)
10864 n->type = NXHERE;
10865 TRACE(("Here document %d\n", n->type));
10866 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010867 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010868 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010869 here->eofmark = wordtext;
10870 here->next = NULL;
10871 if (heredoclist == NULL)
10872 heredoclist = here;
10873 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010874 for (p = heredoclist; p->next; p = p->next)
10875 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010876 p->next = here;
10877 }
10878 } else if (n->type == NTOFD || n->type == NFROMFD) {
10879 fixredir(n, wordtext, 0);
10880 } else {
10881 n->nfile.fname = makename();
10882 }
10883}
Eric Andersencb57d552001-06-28 07:25:16 +000010884
Eric Andersenc470f442003-07-28 09:56:35 +000010885static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010886simplecmd(void)
10887{
10888 union node *args, **app;
10889 union node *n = NULL;
10890 union node *vars, **vpp;
10891 union node **rpp, *redir;
10892 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010893#if ENABLE_ASH_BASH_COMPAT
10894 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000010895 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010896#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010897
10898 args = NULL;
10899 app = &args;
10900 vars = NULL;
10901 vpp = &vars;
10902 redir = NULL;
10903 rpp = &redir;
10904
10905 savecheckkwd = CHKALIAS;
10906 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010907 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010908 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010909 t = readtoken();
10910 switch (t) {
10911#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000010912 case TFUNCTION:
10913 if (peektoken() != TWORD)
10914 raise_error_unexpected_syntax(TWORD);
10915 function_flag = 1;
10916 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010917 case TAND: /* "&&" */
10918 case TOR: /* "||" */
10919 if (!double_brackets_flag) {
10920 tokpushback = 1;
10921 goto out;
10922 }
10923 wordtext = (char *) (t == TAND ? "-a" : "-o");
10924#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010925 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010926 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010927 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010928 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010929 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010930#if ENABLE_ASH_BASH_COMPAT
10931 if (strcmp("[[", wordtext) == 0)
10932 double_brackets_flag = 1;
10933 else if (strcmp("]]", wordtext) == 0)
10934 double_brackets_flag = 0;
10935#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010936 n->narg.backquote = backquotelist;
10937 if (savecheckkwd && isassignment(wordtext)) {
10938 *vpp = n;
10939 vpp = &n->narg.next;
10940 } else {
10941 *app = n;
10942 app = &n->narg.next;
10943 savecheckkwd = 0;
10944 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000010945#if ENABLE_ASH_BASH_COMPAT
10946 if (function_flag) {
10947 checkkwd = CHKNL | CHKKWD;
10948 switch (peektoken()) {
10949 case TBEGIN:
10950 case TIF:
10951 case TCASE:
10952 case TUNTIL:
10953 case TWHILE:
10954 case TFOR:
10955 goto do_func;
10956 case TLP:
10957 function_flag = 0;
10958 break;
10959 case TWORD:
10960 if (strcmp("[[", wordtext) == 0)
10961 goto do_func;
10962 /* fall through */
10963 default:
10964 raise_error_unexpected_syntax(-1);
10965 }
10966 }
10967#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010968 break;
10969 case TREDIR:
10970 *rpp = n = redirnode;
10971 rpp = &n->nfile.next;
10972 parsefname(); /* read name of redirection file */
10973 break;
10974 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000010975 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010976 if (args && app == &args->narg.next
10977 && !vars && !redir
10978 ) {
10979 struct builtincmd *bcmd;
10980 const char *name;
10981
10982 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000010983 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010984 raise_error_unexpected_syntax(TRP);
10985 name = n->narg.text;
10986 if (!goodname(name)
10987 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10988 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010989 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010990 }
10991 n->type = NDEFUN;
10992 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10993 n->narg.next = parse_command();
10994 return n;
10995 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000010996 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010997 /* fall through */
10998 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010999 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011000 goto out;
11001 }
11002 }
11003 out:
11004 *app = NULL;
11005 *vpp = NULL;
11006 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011007 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011008 n->type = NCMD;
11009 n->ncmd.args = args;
11010 n->ncmd.assign = vars;
11011 n->ncmd.redirect = redir;
11012 return n;
11013}
11014
11015static union node *
11016parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011017{
Eric Andersencb57d552001-06-28 07:25:16 +000011018 union node *n1, *n2;
11019 union node *ap, **app;
11020 union node *cp, **cpp;
11021 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011022 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011023 int t;
11024
11025 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011026 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011027
Eric Andersencb57d552001-06-28 07:25:16 +000011028 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011029 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011030 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011031 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011032 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011033 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011034 n1->type = NIF;
11035 n1->nif.test = list(0);
11036 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011037 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011038 n1->nif.ifpart = list(0);
11039 n2 = n1;
11040 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011041 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011042 n2 = n2->nif.elsepart;
11043 n2->type = NIF;
11044 n2->nif.test = list(0);
11045 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011046 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011047 n2->nif.ifpart = list(0);
11048 }
11049 if (lasttoken == TELSE)
11050 n2->nif.elsepart = list(0);
11051 else {
11052 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011053 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011054 }
Eric Andersenc470f442003-07-28 09:56:35 +000011055 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011056 break;
11057 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011058 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011059 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011060 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011061 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011062 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011063 got = readtoken();
11064 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011065 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000011066 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011067 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011068 }
11069 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011070 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011071 break;
11072 }
11073 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011074 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011075 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011076 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011077 n1->type = NFOR;
11078 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011079 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011080 if (readtoken() == TIN) {
11081 app = &ap;
11082 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011083 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011084 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011085 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011086 n2->narg.text = wordtext;
11087 n2->narg.backquote = backquotelist;
11088 *app = n2;
11089 app = &n2->narg.next;
11090 }
11091 *app = NULL;
11092 n1->nfor.args = ap;
11093 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011094 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011095 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011096 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011097 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011098 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011099 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011100 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011101 n1->nfor.args = n2;
11102 /*
11103 * Newline or semicolon here is optional (but note
11104 * that the original Bourne shell only allowed NL).
11105 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011106 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011107 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011108 }
Eric Andersenc470f442003-07-28 09:56:35 +000011109 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011110 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011111 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011112 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011113 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011114 break;
11115 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011116 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011117 n1->type = NCASE;
11118 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011119 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011120 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011121 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011122 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011123 n2->narg.text = wordtext;
11124 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011125 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11126 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011127 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011128 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011129 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011130 checkkwd = CHKNL | CHKKWD;
11131 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011132 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011133 if (lasttoken == TLP)
11134 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011135 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011136 cp->type = NCLIST;
11137 app = &cp->nclist.pattern;
11138 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011139 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011140 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011141 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011142 ap->narg.text = wordtext;
11143 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011144 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011145 break;
11146 app = &ap->narg.next;
11147 readtoken();
11148 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011149 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011150 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011151 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011152 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011153
Eric Andersenc470f442003-07-28 09:56:35 +000011154 cpp = &cp->nclist.next;
11155
11156 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011157 t = readtoken();
11158 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011159 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011160 raise_error_unexpected_syntax(TENDCASE);
11161 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011162 }
Eric Andersenc470f442003-07-28 09:56:35 +000011163 }
Eric Andersencb57d552001-06-28 07:25:16 +000011164 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011165 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011166 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011167 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011168 n1->type = NSUBSHELL;
11169 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011170 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011171 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011172 break;
11173 case TBEGIN:
11174 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011175 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011176 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011177 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011178 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011179 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011180 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011181 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011182 }
11183
Eric Andersenc470f442003-07-28 09:56:35 +000011184 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011185 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011186
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011187 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011188 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011189 checkkwd = CHKKWD | CHKALIAS;
11190 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011191 while (readtoken() == TREDIR) {
11192 *rpp = n2 = redirnode;
11193 rpp = &n2->nfile.next;
11194 parsefname();
11195 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011196 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011197 *rpp = NULL;
11198 if (redir) {
11199 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011200 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011201 n2->type = NREDIR;
11202 n2->nredir.n = n1;
11203 n1 = n2;
11204 }
11205 n1->nredir.redirect = redir;
11206 }
Eric Andersencb57d552001-06-28 07:25:16 +000011207 return n1;
11208}
11209
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011210#if ENABLE_ASH_BASH_COMPAT
11211static int decode_dollar_squote(void)
11212{
11213 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11214 int c, cnt;
11215 char *p;
11216 char buf[4];
11217
11218 c = pgetc();
11219 p = strchr(C_escapes, c);
11220 if (p) {
11221 buf[0] = c;
11222 p = buf;
11223 cnt = 3;
11224 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11225 do {
11226 c = pgetc();
11227 *++p = c;
11228 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11229 pungetc();
11230 } else if (c == 'x') { /* \xHH */
11231 do {
11232 c = pgetc();
11233 *++p = c;
11234 } while (isxdigit(c) && --cnt);
11235 pungetc();
11236 if (cnt == 3) { /* \x but next char is "bad" */
11237 c = 'x';
11238 goto unrecognized;
11239 }
11240 } else { /* simple seq like \\ or \t */
11241 p++;
11242 }
11243 *p = '\0';
11244 p = buf;
11245 c = bb_process_escape_sequence((void*)&p);
11246 } else { /* unrecognized "\z": print both chars unless ' or " */
11247 if (c != '\'' && c != '"') {
11248 unrecognized:
11249 c |= 0x100; /* "please encode \, then me" */
11250 }
11251 }
11252 return c;
11253}
11254#endif
11255
Eric Andersencb57d552001-06-28 07:25:16 +000011256/*
11257 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11258 * is not NULL, read a here document. In the latter case, eofmark is the
11259 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011260 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011261 * is the first character of the input token or document.
11262 *
11263 * Because C does not have internal subroutines, I have simulated them
11264 * using goto's to implement the subroutine linkage. The following macros
11265 * will run code that appears at the end of readtoken1.
11266 */
Eric Andersen2870d962001-07-02 17:27:21 +000011267#define CHECKEND() {goto checkend; checkend_return:;}
11268#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11269#define PARSESUB() {goto parsesub; parsesub_return:;}
11270#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11271#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11272#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011273static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011274readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011275{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011276 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011277 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011278 char *out;
11279 int len;
11280 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011281 struct nodelist *bqlist;
11282 smallint quotef;
11283 smallint dblquote;
11284 smallint oldstyle;
11285 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011286#if ENABLE_ASH_EXPAND_PRMT
11287 smallint pssyntax; /* we are expanding a prompt string */
11288#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011289 int varnest; /* levels of variables expansion */
11290 int arinest; /* levels of arithmetic expansion */
11291 int parenlevel; /* levels of parens in arithmetic */
11292 int dqvarnest; /* levels of variables expansion within double quotes */
11293
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011294 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011295
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011296 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011297 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011298 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011299 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011300#if ENABLE_ASH_EXPAND_PRMT
11301 pssyntax = (syntax == PSSYNTAX);
11302 if (pssyntax)
11303 syntax = DQSYNTAX;
11304#endif
11305 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011306 varnest = 0;
11307 arinest = 0;
11308 parenlevel = 0;
11309 dqvarnest = 0;
11310
11311 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011312 loop:
11313 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011314 CHECKEND(); /* set c to PEOF if at end of here document */
11315 for (;;) { /* until end of line or end of word */
11316 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11317 switch (SIT(c, syntax)) {
11318 case CNL: /* '\n' */
11319 if (syntax == BASESYNTAX)
11320 goto endword; /* exit outer loop */
11321 USTPUTC(c, out);
11322 g_parsefile->linno++;
11323 setprompt_if(doprompt, 2);
11324 c = pgetc();
11325 goto loop; /* continue outer loop */
11326 case CWORD:
11327 USTPUTC(c, out);
11328 break;
11329 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011330#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011331 if (c == '\\' && bash_dollar_squote) {
11332 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011333 if (c == '\0') {
11334 /* skip $'\000', $'\x00' (like bash) */
11335 break;
11336 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011337 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011338 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011339 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011340 if (eofmark == NULL || dblquote)
11341 USTPUTC(CTLESC, out);
11342 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011343 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011344 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011345#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011346 if (eofmark == NULL || dblquote)
11347 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011348 USTPUTC(c, out);
11349 break;
11350 case CBACK: /* backslash */
11351 c = pgetc_without_PEOA();
11352 if (c == PEOF) {
11353 USTPUTC(CTLESC, out);
11354 USTPUTC('\\', out);
11355 pungetc();
11356 } else if (c == '\n') {
11357 setprompt_if(doprompt, 2);
11358 } else {
11359#if ENABLE_ASH_EXPAND_PRMT
11360 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011361 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011362 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011363 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011364#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011365 /* Backslash is retained if we are in "str" and next char isn't special */
11366 if (dblquote
11367 && c != '\\'
11368 && c != '`'
11369 && c != '$'
11370 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011371 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011372 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011373 }
Ron Yorston549deab2015-05-18 09:57:51 +020011374 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011375 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011376 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011377 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011378 break;
11379 case CSQUOTE:
11380 syntax = SQSYNTAX;
11381 quotemark:
11382 if (eofmark == NULL) {
11383 USTPUTC(CTLQUOTEMARK, out);
11384 }
11385 break;
11386 case CDQUOTE:
11387 syntax = DQSYNTAX;
11388 dblquote = 1;
11389 goto quotemark;
11390 case CENDQUOTE:
11391 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011392 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011393 USTPUTC(c, out);
11394 } else {
11395 if (dqvarnest == 0) {
11396 syntax = BASESYNTAX;
11397 dblquote = 0;
11398 }
11399 quotef = 1;
11400 goto quotemark;
11401 }
11402 break;
11403 case CVAR: /* '$' */
11404 PARSESUB(); /* parse substitution */
11405 break;
11406 case CENDVAR: /* '}' */
11407 if (varnest > 0) {
11408 varnest--;
11409 if (dqvarnest > 0) {
11410 dqvarnest--;
11411 }
11412 c = CTLENDVAR;
11413 }
11414 USTPUTC(c, out);
11415 break;
11416#if ENABLE_SH_MATH_SUPPORT
11417 case CLP: /* '(' in arithmetic */
11418 parenlevel++;
11419 USTPUTC(c, out);
11420 break;
11421 case CRP: /* ')' in arithmetic */
11422 if (parenlevel > 0) {
11423 parenlevel--;
11424 } else {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011425 if (pgetc_eatbnl() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011426 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011427 if (--arinest == 0) {
11428 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011429 }
11430 } else {
11431 /*
11432 * unbalanced parens
11433 * (don't 2nd guess - no error)
11434 */
11435 pungetc();
11436 }
11437 }
11438 USTPUTC(c, out);
11439 break;
11440#endif
11441 case CBQUOTE: /* '`' */
11442 PARSEBACKQOLD();
11443 break;
11444 case CENDFILE:
11445 goto endword; /* exit outer loop */
11446 case CIGN:
11447 break;
11448 default:
11449 if (varnest == 0) {
11450#if ENABLE_ASH_BASH_COMPAT
11451 if (c == '&') {
Denys Vlasenko459293b2016-09-29 17:58:58 +020011452//Can't call pgetc_eatbnl() here, this requires three-deep pungetc()
Denys Vlasenko958581a2010-09-12 15:04:27 +020011453 if (pgetc() == '>')
11454 c = 0x100 + '>'; /* flag &> */
11455 pungetc();
11456 }
11457#endif
11458 goto endword; /* exit outer loop */
11459 }
11460 IF_ASH_ALIAS(if (c != PEOA))
11461 USTPUTC(c, out);
11462 }
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011463 c = pgetc();
Denys Vlasenko958581a2010-09-12 15:04:27 +020011464 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011465 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011466
Mike Frysinger98c52642009-04-02 10:02:37 +000011467#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011468 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011469 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011470#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011471 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011472 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011473 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011474 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011475 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011476 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011477 }
11478 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011479 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011480 out = stackblock();
11481 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011482 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011483 && quotef == 0
11484 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011485 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011486 PARSEREDIR(); /* passed as params: out, c */
11487 lasttoken = TREDIR;
11488 return lasttoken;
11489 }
11490 /* else: non-number X seen, interpret it
11491 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011492 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011493 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011494 }
11495 quoteflag = quotef;
11496 backquotelist = bqlist;
11497 grabstackblock(len);
11498 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011499 lasttoken = TWORD;
11500 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011501/* end of readtoken routine */
11502
Eric Andersencb57d552001-06-28 07:25:16 +000011503/*
11504 * Check to see whether we are at the end of the here document. When this
11505 * is called, c is set to the first character of the next input line. If
11506 * we are at the end of the here document, this routine sets the c to PEOF.
11507 */
Eric Andersenc470f442003-07-28 09:56:35 +000011508checkend: {
11509 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011510#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011511 if (c == PEOA)
11512 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011513#endif
11514 if (striptabs) {
11515 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011516 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011517 }
Eric Andersenc470f442003-07-28 09:56:35 +000011518 }
11519 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011520 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011521 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011522
Eric Andersenc470f442003-07-28 09:56:35 +000011523 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011524 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11525 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011526 if (*p == '\n' && *q == '\0') {
11527 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011528 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011529 needprompt = doprompt;
11530 } else {
11531 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011532 }
11533 }
11534 }
11535 }
Eric Andersenc470f442003-07-28 09:56:35 +000011536 goto checkend_return;
11537}
Eric Andersencb57d552001-06-28 07:25:16 +000011538
Eric Andersencb57d552001-06-28 07:25:16 +000011539/*
11540 * Parse a redirection operator. The variable "out" points to a string
11541 * specifying the fd to be redirected. The variable "c" contains the
11542 * first character of the redirection operator.
11543 */
Eric Andersenc470f442003-07-28 09:56:35 +000011544parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011545 /* out is already checked to be a valid number or "" */
11546 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011547 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011548
Denis Vlasenko597906c2008-02-20 16:38:54 +000011549 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011550 if (c == '>') {
11551 np->nfile.fd = 1;
11552 c = pgetc();
11553 if (c == '>')
11554 np->type = NAPPEND;
11555 else if (c == '|')
11556 np->type = NCLOBBER;
11557 else if (c == '&')
11558 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011559 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011560 else {
11561 np->type = NTO;
11562 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011563 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011564 }
11565#if ENABLE_ASH_BASH_COMPAT
11566 else if (c == 0x100 + '>') { /* this flags &> redirection */
11567 np->nfile.fd = 1;
11568 pgetc(); /* this is '>', no need to check */
11569 np->type = NTO2;
11570 }
11571#endif
11572 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011573 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011574 c = pgetc();
11575 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011576 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011577 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011578 np = stzalloc(sizeof(struct nhere));
11579 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011580 }
11581 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011582 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011583 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011584 c = pgetc();
11585 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011586 heredoc->striptabs = 1;
11587 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011588 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011589 pungetc();
11590 }
11591 break;
11592
11593 case '&':
11594 np->type = NFROMFD;
11595 break;
11596
11597 case '>':
11598 np->type = NFROMTO;
11599 break;
11600
11601 default:
11602 np->type = NFROM;
11603 pungetc();
11604 break;
11605 }
Eric Andersencb57d552001-06-28 07:25:16 +000011606 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011607 if (fd >= 0)
11608 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011609 redirnode = np;
11610 goto parseredir_return;
11611}
Eric Andersencb57d552001-06-28 07:25:16 +000011612
Eric Andersencb57d552001-06-28 07:25:16 +000011613/*
11614 * Parse a substitution. At this point, we have read the dollar sign
11615 * and nothing else.
11616 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011617
11618/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11619 * (assuming ascii char codes, as the original implementation did) */
11620#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011621 (((unsigned)(c) - 33 < 32) \
11622 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011623parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011624 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011625 int typeloc;
11626 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011627
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011628 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011629 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011630 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011631 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011632#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011633 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011634 bash_dollar_squote = 1;
11635 else
11636#endif
11637 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011638 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011639 } else if (c == '(') {
11640 /* $(command) or $((arith)) */
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011641 if (pgetc_eatbnl() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011642#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011643 PARSEARITH();
11644#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011645 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011646#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011647 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011648 pungetc();
11649 PARSEBACKQNEW();
11650 }
11651 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011652 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011653 USTPUTC(CTLVAR, out);
11654 typeloc = out - (char *)stackblock();
11655 USTPUTC(VSNORMAL, out);
11656 subtype = VSNORMAL;
11657 if (c == '{') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011658 c = pgetc_eatbnl();
Eric Andersenc470f442003-07-28 09:56:35 +000011659 if (c == '#') {
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011660 c = pgetc_eatbnl();
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011661 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011662 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011663 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011664 subtype = VSLENGTH; /* ${#VAR} */
11665 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011666 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011667 }
Eric Andersenc470f442003-07-28 09:56:35 +000011668 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011669 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011670 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011671 do {
11672 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011673 c = pgetc_eatbnl();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011674 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011675 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011676 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011677 do {
11678 STPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011679 c = pgetc_eatbnl();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011680 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011681 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011682 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011683 USTPUTC(c, out);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011684 c = pgetc_eatbnl();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011685 } else {
11686 badsub:
11687 raise_error_syntax("bad substitution");
11688 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011689 if (c != '}' && subtype == VSLENGTH) {
11690 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011691 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011692 }
Eric Andersencb57d552001-06-28 07:25:16 +000011693
Eric Andersenc470f442003-07-28 09:56:35 +000011694 STPUTC('=', out);
11695 flags = 0;
11696 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011697 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011698 /* ${VAR...} but not $VAR or ${#VAR} */
11699 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011700 switch (c) {
11701 case ':':
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011702 c = pgetc_eatbnl();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011703#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011704 /* This check is only needed to not misinterpret
11705 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11706 * constructs.
11707 */
11708 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011709 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011710 pungetc();
11711 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011712 }
11713#endif
11714 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011715 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011716 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011717 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011718 if (p == NULL)
11719 goto badsub;
11720 subtype = p - types + VSNORMAL;
11721 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011722 }
Eric Andersenc470f442003-07-28 09:56:35 +000011723 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011724 case '#': {
11725 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011726 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011727 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011728 if (c != cc)
11729 goto do_pungetc;
11730 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011731 break;
11732 }
11733#if ENABLE_ASH_BASH_COMPAT
11734 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011735 /* ${v/[/]pattern/repl} */
11736//TODO: encode pattern and repl separately.
11737// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011738 subtype = VSREPLACE;
Denys Vlasenko73c3e072016-09-29 17:17:04 +020011739 c = pgetc_eatbnl();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011740 if (c != '/')
11741 goto do_pungetc;
11742 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011743 break;
11744#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011745 }
Eric Andersenc470f442003-07-28 09:56:35 +000011746 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011747 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011748 pungetc();
11749 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011750 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011751 if (subtype != VSNORMAL) {
11752 varnest++;
Ron Yorston7e4ed262015-05-18 09:54:43 +020011753 if (dblquote) {
Eric Andersenc470f442003-07-28 09:56:35 +000011754 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011755 }
11756 }
11757 }
Eric Andersenc470f442003-07-28 09:56:35 +000011758 goto parsesub_return;
11759}
Eric Andersencb57d552001-06-28 07:25:16 +000011760
Eric Andersencb57d552001-06-28 07:25:16 +000011761/*
11762 * Called to parse command substitutions. Newstyle is set if the command
11763 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11764 * list of commands (passed by reference), and savelen is the number of
11765 * characters on the top of the stack which must be preserved.
11766 */
Eric Andersenc470f442003-07-28 09:56:35 +000011767parsebackq: {
11768 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011769 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011770 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011771 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011772 smallint saveprompt = 0;
11773
Eric Andersenc470f442003-07-28 09:56:35 +000011774 str = NULL;
11775 savelen = out - (char *)stackblock();
11776 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011777 /*
11778 * FIXME: this can allocate very large block on stack and SEGV.
11779 * Example:
11780 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011781 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011782 * a hundred command substitutions stack overflows.
11783 * With larger prepended string, SEGV happens sooner.
11784 */
Ron Yorston072fc602015-07-01 16:46:18 +010011785 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011786 memcpy(str, stackblock(), savelen);
11787 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011788
Eric Andersenc470f442003-07-28 09:56:35 +000011789 if (oldstyle) {
11790 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011791 * treatment to some slashes, and then push the string and
11792 * reread it as input, interpreting it normally.
11793 */
Eric Andersenc470f442003-07-28 09:56:35 +000011794 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011795 size_t psavelen;
11796 char *pstr;
11797
Eric Andersenc470f442003-07-28 09:56:35 +000011798 STARTSTACKSTR(pout);
11799 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011800 int pc;
11801
11802 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011803 pc = pgetc();
11804 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011805 case '`':
11806 goto done;
11807
11808 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011809 pc = pgetc();
11810 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011811 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011812 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011813 /*
11814 * If eating a newline, avoid putting
11815 * the newline into the new character
11816 * stream (via the STPUTC after the
11817 * switch).
11818 */
11819 continue;
11820 }
11821 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011822 && (!dblquote || pc != '"')
11823 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011824 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011825 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011826 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011827 break;
11828 }
11829 /* fall through */
11830
11831 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011832 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011833 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011834 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011835
11836 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011837 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011838 needprompt = doprompt;
11839 break;
11840
11841 default:
11842 break;
11843 }
11844 STPUTC(pc, pout);
11845 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011846 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011847 STPUTC('\0', pout);
11848 psavelen = pout - (char *)stackblock();
11849 if (psavelen > 0) {
11850 pstr = grabstackstr(pout);
11851 setinputstring(pstr);
11852 }
11853 }
11854 nlpp = &bqlist;
11855 while (*nlpp)
11856 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011857 *nlpp = stzalloc(sizeof(**nlpp));
11858 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011859
11860 if (oldstyle) {
11861 saveprompt = doprompt;
11862 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011863 }
11864
Eric Andersenc470f442003-07-28 09:56:35 +000011865 n = list(2);
11866
11867 if (oldstyle)
11868 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011869 else if (readtoken() != TRP)
11870 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011871
11872 (*nlpp)->n = n;
11873 if (oldstyle) {
11874 /*
11875 * Start reading from old file again, ignoring any pushed back
11876 * tokens left from the backquote parsing
11877 */
11878 popfile();
11879 tokpushback = 0;
11880 }
11881 while (stackblocksize() <= savelen)
11882 growstackblock();
11883 STARTSTACKSTR(out);
11884 if (str) {
11885 memcpy(out, str, savelen);
11886 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011887 }
Ron Yorston549deab2015-05-18 09:57:51 +020011888 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011889 if (oldstyle)
11890 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011891 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011892}
11893
Mike Frysinger98c52642009-04-02 10:02:37 +000011894#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011895/*
11896 * Parse an arithmetic expansion (indicate start of one and set state)
11897 */
Eric Andersenc470f442003-07-28 09:56:35 +000011898parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011899 if (++arinest == 1) {
11900 prevsyntax = syntax;
11901 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011902 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011903 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011904 goto parsearith_return;
11905}
11906#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011907} /* end of readtoken */
11908
Eric Andersencb57d552001-06-28 07:25:16 +000011909/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011910 * Read the next input token.
11911 * If the token is a word, we set backquotelist to the list of cmds in
11912 * backquotes. We set quoteflag to true if any part of the word was
11913 * quoted.
11914 * If the token is TREDIR, then we set redirnode to a structure containing
11915 * the redirection.
11916 * In all cases, the variable startlinno is set to the number of the line
11917 * on which the token starts.
11918 *
11919 * [Change comment: here documents and internal procedures]
11920 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11921 * word parsing code into a separate routine. In this case, readtoken
11922 * doesn't need to have any internal procedures, but parseword does.
11923 * We could also make parseoperator in essence the main routine, and
11924 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011925 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011926#define NEW_xxreadtoken
11927#ifdef NEW_xxreadtoken
11928/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011929static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011930 '\n', '(', ')', /* singles */
11931 '&', '|', ';', /* doubles */
11932 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011933};
Eric Andersencb57d552001-06-28 07:25:16 +000011934
Denis Vlasenko834dee72008-10-07 09:18:30 +000011935#define xxreadtoken_singles 3
11936#define xxreadtoken_doubles 3
11937
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011938static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011939 TNL, TLP, TRP, /* only single occurrence allowed */
11940 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11941 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011942 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011943};
11944
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011945static int
11946xxreadtoken(void)
11947{
11948 int c;
11949
11950 if (tokpushback) {
11951 tokpushback = 0;
11952 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011953 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011954 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011955 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011956 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020011957 c = pgetc();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011958 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011959 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011960
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011961 if (c == '#') {
11962 while ((c = pgetc()) != '\n' && c != PEOF)
11963 continue;
11964 pungetc();
11965 } else if (c == '\\') {
11966 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011967 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011968 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011969 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011970 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011971 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011972 } else {
11973 const char *p;
11974
11975 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11976 if (c != PEOF) {
11977 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011978 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011979 needprompt = doprompt;
11980 }
11981
11982 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011983 if (p == NULL)
11984 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011985
Denis Vlasenko834dee72008-10-07 09:18:30 +000011986 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11987 int cc = pgetc();
11988 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011989 p += xxreadtoken_doubles + 1;
11990 } else {
11991 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011992#if ENABLE_ASH_BASH_COMPAT
11993 if (c == '&' && cc == '>') /* &> */
11994 break; /* return readtoken1(...) */
11995#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011996 }
11997 }
11998 }
11999 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
12000 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012001 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012002 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012003
12004 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012005}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012006#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012007#define RETURN(token) return lasttoken = token
12008static int
12009xxreadtoken(void)
12010{
12011 int c;
12012
12013 if (tokpushback) {
12014 tokpushback = 0;
12015 return lasttoken;
12016 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012017 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012018 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012019 for (;;) { /* until token or start of word found */
Denys Vlasenko3b4d04b2016-09-29 02:11:19 +020012020 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012021 switch (c) {
12022 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012023 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012024 continue;
12025 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012026 while ((c = pgetc()) != '\n' && c != PEOF)
12027 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012028 pungetc();
12029 continue;
12030 case '\\':
12031 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012032 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012033 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012034 continue;
12035 }
12036 pungetc();
12037 goto breakloop;
12038 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012039 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012040 needprompt = doprompt;
12041 RETURN(TNL);
12042 case PEOF:
12043 RETURN(TEOF);
12044 case '&':
12045 if (pgetc() == '&')
12046 RETURN(TAND);
12047 pungetc();
12048 RETURN(TBACKGND);
12049 case '|':
12050 if (pgetc() == '|')
12051 RETURN(TOR);
12052 pungetc();
12053 RETURN(TPIPE);
12054 case ';':
12055 if (pgetc() == ';')
12056 RETURN(TENDCASE);
12057 pungetc();
12058 RETURN(TSEMI);
12059 case '(':
12060 RETURN(TLP);
12061 case ')':
12062 RETURN(TRP);
12063 default:
12064 goto breakloop;
12065 }
12066 }
12067 breakloop:
12068 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12069#undef RETURN
12070}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012071#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012072
12073static int
12074readtoken(void)
12075{
12076 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012077 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012078#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012079 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012080#endif
12081
12082#if ENABLE_ASH_ALIAS
12083 top:
12084#endif
12085
12086 t = xxreadtoken();
12087
12088 /*
12089 * eat newlines
12090 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012091 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012092 while (t == TNL) {
12093 parseheredoc();
12094 t = xxreadtoken();
12095 }
12096 }
12097
12098 if (t != TWORD || quoteflag) {
12099 goto out;
12100 }
12101
12102 /*
12103 * check for keywords
12104 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012105 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012106 const char *const *pp;
12107
12108 pp = findkwd(wordtext);
12109 if (pp) {
12110 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012111 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012112 goto out;
12113 }
12114 }
12115
12116 if (checkkwd & CHKALIAS) {
12117#if ENABLE_ASH_ALIAS
12118 struct alias *ap;
12119 ap = lookupalias(wordtext, 1);
12120 if (ap != NULL) {
12121 if (*ap->val) {
12122 pushstring(ap->val, ap);
12123 }
12124 goto top;
12125 }
12126#endif
12127 }
12128 out:
12129 checkkwd = 0;
12130#if DEBUG
12131 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012132 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012133 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012134 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012135#endif
12136 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012137}
12138
Ron Yorstonc0e00762015-10-29 11:30:55 +000012139static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012140peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012141{
12142 int t;
12143
12144 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012145 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012146 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012147}
Eric Andersencb57d552001-06-28 07:25:16 +000012148
12149/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012150 * Read and parse a command. Returns NODE_EOF on end of file.
12151 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012152 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012153static union node *
12154parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012155{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012156 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012157 checkkwd = 0;
12158 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012159 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012160 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012161 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012162 return list(1);
12163}
12164
12165/*
12166 * Input any here documents.
12167 */
12168static void
12169parseheredoc(void)
12170{
12171 struct heredoc *here;
12172 union node *n;
12173
12174 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012175 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012176
12177 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012178 setprompt_if(needprompt, 2);
12179 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012180 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012181 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012182 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012183 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012184 n->narg.text = wordtext;
12185 n->narg.backquote = backquotelist;
12186 here->here->nhere.doc = n;
12187 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012188 }
Eric Andersencb57d552001-06-28 07:25:16 +000012189}
12190
12191
12192/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012193 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012194 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012195#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012196static const char *
12197expandstr(const char *ps)
12198{
12199 union node n;
12200
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012201 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12202 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012203 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012204 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012205 popfile();
12206
12207 n.narg.type = NARG;
12208 n.narg.next = NULL;
12209 n.narg.text = wordtext;
12210 n.narg.backquote = backquotelist;
12211
Ron Yorston549deab2015-05-18 09:57:51 +020012212 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012213 return stackblock();
12214}
12215#endif
12216
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012217/*
12218 * Execute a command or commands contained in a string.
12219 */
12220static int
12221evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012222{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012223 union node *n;
12224 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012225 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012226
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012227 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012228 setinputstring(s);
12229 setstackmark(&smark);
12230
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012231 status = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012232 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012233 int i;
12234
12235 i = evaltree(n, 0);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012236 if (n)
12237 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012238 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012239 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012240 break;
12241 }
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012242 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012243 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012244 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012245
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012246 evalskip &= mask;
12247 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012248}
12249
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012250/*
12251 * The eval command.
12252 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012253static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012254evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012255{
12256 char *p;
12257 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012258
Denis Vlasenko68404f12008-03-17 09:00:54 +000012259 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012260 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012261 argv += 2;
12262 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012263 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012264 for (;;) {
12265 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012266 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012267 if (p == NULL)
12268 break;
12269 STPUTC(' ', concat);
12270 }
12271 STPUTC('\0', concat);
12272 p = grabstackstr(concat);
12273 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012274 return evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012275 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012276 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012277}
12278
12279/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012280 * Read and execute commands.
12281 * "Top" is nonzero for the top level command loop;
12282 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012283 */
12284static int
12285cmdloop(int top)
12286{
12287 union node *n;
12288 struct stackmark smark;
12289 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012290 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012291 int numeof = 0;
12292
12293 TRACE(("cmdloop(%d) called\n", top));
12294 for (;;) {
12295 int skip;
12296
12297 setstackmark(&smark);
12298#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012299 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012300 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012301#endif
12302 inter = 0;
12303 if (iflag && top) {
12304 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012305 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012306 }
12307 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012308#if DEBUG
12309 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012310 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012311#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012312 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012313 if (!top || numeof >= 50)
12314 break;
12315 if (!stoppedjobs()) {
12316 if (!Iflag)
12317 break;
12318 out2str("\nUse \"exit\" to leave shell.\n");
12319 }
12320 numeof++;
12321 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012322 int i;
12323
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012324 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12325 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012326 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012327 i = evaltree(n, 0);
12328 if (n)
12329 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012330 }
12331 popstackmark(&smark);
12332 skip = evalskip;
12333
12334 if (skip) {
12335 evalskip = 0;
12336 return skip & SKIPEVAL;
12337 }
12338 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012339 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012340}
12341
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012342/*
12343 * Take commands from a file. To be compatible we should do a path
12344 * search for the file, which is necessary to find sub-commands.
12345 */
12346static char *
12347find_dot_file(char *name)
12348{
12349 char *fullname;
12350 const char *path = pathval();
12351 struct stat statb;
12352
12353 /* don't try this for absolute or relative paths */
12354 if (strchr(name, '/'))
12355 return name;
12356
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012357 /* IIRC standards do not say whether . is to be searched.
12358 * And it is even smaller this way, making it unconditional for now:
12359 */
12360 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12361 fullname = name;
12362 goto try_cur_dir;
12363 }
12364
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012365 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012366 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012367 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12368 /*
12369 * Don't bother freeing here, since it will
12370 * be freed by the caller.
12371 */
12372 return fullname;
12373 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012374 if (fullname != name)
12375 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012376 }
12377
12378 /* not found in the PATH */
12379 ash_msg_and_raise_error("%s: not found", name);
12380 /* NOTREACHED */
12381}
12382
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012383static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012384dotcmd(int argc, char **argv)
12385{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012386 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012387 struct strlist *sp;
12388 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012389
12390 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012391 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012392
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012393 if (!argv[1]) {
12394 /* bash says: "bash: .: filename argument required" */
12395 return 2; /* bash compat */
12396 }
12397
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012398 /* "false; . empty_file; echo $?" should print 0, not 1: */
12399 exitstatus = 0;
12400
Denys Vlasenko091f8312013-03-17 14:25:22 +010012401 /* This aborts if file isn't found, which is POSIXly correct.
12402 * bash returns exitcode 1 instead.
12403 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012404 fullname = find_dot_file(argv[1]);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012405 argv += 2;
12406 argc -= 2;
12407 if (argc) { /* argc > 0, argv[0] != NULL */
12408 saveparam = shellparam;
12409 shellparam.malloced = 0;
12410 shellparam.nparam = argc;
12411 shellparam.p = argv;
12412 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012413
Denys Vlasenko091f8312013-03-17 14:25:22 +010012414 /* This aborts if file can't be opened, which is POSIXly correct.
12415 * bash returns exitcode 1 instead.
12416 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012417 setinputfile(fullname, INPUT_PUSH_FILE);
12418 commandname = fullname;
12419 cmdloop(0);
12420 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012421
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012422 if (argc) {
12423 freeparam(&shellparam);
12424 shellparam = saveparam;
12425 };
12426
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012427 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012428}
12429
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012430static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012431exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012432{
12433 if (stoppedjobs())
12434 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012435 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012436 exitstatus = number(argv[1]);
12437 raise_exception(EXEXIT);
12438 /* NOTREACHED */
12439}
12440
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012441/*
12442 * Read a file containing shell functions.
12443 */
12444static void
12445readcmdfile(char *name)
12446{
12447 setinputfile(name, INPUT_PUSH_FILE);
12448 cmdloop(0);
12449 popfile();
12450}
12451
12452
Denis Vlasenkocc571512007-02-23 21:10:35 +000012453/* ============ find_command inplementation */
12454
12455/*
12456 * Resolve a command name. If you change this routine, you may have to
12457 * change the shellexec routine as well.
12458 */
12459static void
12460find_command(char *name, struct cmdentry *entry, int act, const char *path)
12461{
12462 struct tblentry *cmdp;
12463 int idx;
12464 int prev;
12465 char *fullname;
12466 struct stat statb;
12467 int e;
12468 int updatetbl;
12469 struct builtincmd *bcmd;
12470
12471 /* If name contains a slash, don't use PATH or hash table */
12472 if (strchr(name, '/') != NULL) {
12473 entry->u.index = -1;
12474 if (act & DO_ABS) {
12475 while (stat(name, &statb) < 0) {
12476#ifdef SYSV
12477 if (errno == EINTR)
12478 continue;
12479#endif
12480 entry->cmdtype = CMDUNKNOWN;
12481 return;
12482 }
12483 }
12484 entry->cmdtype = CMDNORMAL;
12485 return;
12486 }
12487
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012488/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012489
12490 updatetbl = (path == pathval());
12491 if (!updatetbl) {
12492 act |= DO_ALTPATH;
12493 if (strstr(path, "%builtin") != NULL)
12494 act |= DO_ALTBLTIN;
12495 }
12496
12497 /* If name is in the table, check answer will be ok */
12498 cmdp = cmdlookup(name, 0);
12499 if (cmdp != NULL) {
12500 int bit;
12501
12502 switch (cmdp->cmdtype) {
12503 default:
12504#if DEBUG
12505 abort();
12506#endif
12507 case CMDNORMAL:
12508 bit = DO_ALTPATH;
12509 break;
12510 case CMDFUNCTION:
12511 bit = DO_NOFUNC;
12512 break;
12513 case CMDBUILTIN:
12514 bit = DO_ALTBLTIN;
12515 break;
12516 }
12517 if (act & bit) {
12518 updatetbl = 0;
12519 cmdp = NULL;
12520 } else if (cmdp->rehash == 0)
12521 /* if not invalidated by cd, we're done */
12522 goto success;
12523 }
12524
12525 /* If %builtin not in path, check for builtin next */
12526 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012527 if (bcmd) {
12528 if (IS_BUILTIN_REGULAR(bcmd))
12529 goto builtin_success;
12530 if (act & DO_ALTPATH) {
12531 if (!(act & DO_ALTBLTIN))
12532 goto builtin_success;
12533 } else if (builtinloc <= 0) {
12534 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012535 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012536 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012537
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012538#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012539 {
12540 int applet_no = find_applet_by_name(name);
12541 if (applet_no >= 0) {
12542 entry->cmdtype = CMDNORMAL;
12543 entry->u.index = -2 - applet_no;
12544 return;
12545 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012546 }
12547#endif
12548
Denis Vlasenkocc571512007-02-23 21:10:35 +000012549 /* We have to search path. */
12550 prev = -1; /* where to start */
12551 if (cmdp && cmdp->rehash) { /* doing a rehash */
12552 if (cmdp->cmdtype == CMDBUILTIN)
12553 prev = builtinloc;
12554 else
12555 prev = cmdp->param.index;
12556 }
12557
12558 e = ENOENT;
12559 idx = -1;
12560 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012561 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012562 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012563 /* NB: code below will still use fullname
12564 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012565 idx++;
12566 if (pathopt) {
12567 if (prefix(pathopt, "builtin")) {
12568 if (bcmd)
12569 goto builtin_success;
12570 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012571 }
12572 if ((act & DO_NOFUNC)
12573 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012574 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012575 continue;
12576 }
12577 }
12578 /* if rehash, don't redo absolute path names */
12579 if (fullname[0] == '/' && idx <= prev) {
12580 if (idx < prev)
12581 continue;
12582 TRACE(("searchexec \"%s\": no change\n", name));
12583 goto success;
12584 }
12585 while (stat(fullname, &statb) < 0) {
12586#ifdef SYSV
12587 if (errno == EINTR)
12588 continue;
12589#endif
12590 if (errno != ENOENT && errno != ENOTDIR)
12591 e = errno;
12592 goto loop;
12593 }
12594 e = EACCES; /* if we fail, this will be the error */
12595 if (!S_ISREG(statb.st_mode))
12596 continue;
12597 if (pathopt) { /* this is a %func directory */
12598 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012599 /* NB: stalloc will return space pointed by fullname
12600 * (because we don't have any intervening allocations
12601 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012602 readcmdfile(fullname);
12603 cmdp = cmdlookup(name, 0);
12604 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12605 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12606 stunalloc(fullname);
12607 goto success;
12608 }
12609 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12610 if (!updatetbl) {
12611 entry->cmdtype = CMDNORMAL;
12612 entry->u.index = idx;
12613 return;
12614 }
12615 INT_OFF;
12616 cmdp = cmdlookup(name, 1);
12617 cmdp->cmdtype = CMDNORMAL;
12618 cmdp->param.index = idx;
12619 INT_ON;
12620 goto success;
12621 }
12622
12623 /* We failed. If there was an entry for this command, delete it */
12624 if (cmdp && updatetbl)
12625 delete_cmd_entry();
12626 if (act & DO_ERR)
12627 ash_msg("%s: %s", name, errmsg(e, "not found"));
12628 entry->cmdtype = CMDUNKNOWN;
12629 return;
12630
12631 builtin_success:
12632 if (!updatetbl) {
12633 entry->cmdtype = CMDBUILTIN;
12634 entry->u.cmd = bcmd;
12635 return;
12636 }
12637 INT_OFF;
12638 cmdp = cmdlookup(name, 1);
12639 cmdp->cmdtype = CMDBUILTIN;
12640 cmdp->param.cmd = bcmd;
12641 INT_ON;
12642 success:
12643 cmdp->rehash = 0;
12644 entry->cmdtype = cmdp->cmdtype;
12645 entry->u = cmdp->param;
12646}
12647
12648
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012649/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012650
Eric Andersencb57d552001-06-28 07:25:16 +000012651/*
Eric Andersencb57d552001-06-28 07:25:16 +000012652 * The trap builtin.
12653 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012654static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012655trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012656{
12657 char *action;
12658 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012659 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012660
Eric Andersenc470f442003-07-28 09:56:35 +000012661 nextopt(nullstr);
12662 ap = argptr;
12663 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012664 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012665 char *tr = trap_ptr[signo];
12666 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012667 /* note: bash adds "SIG", but only if invoked
12668 * as "bash". If called as "sh", or if set -o posix,
12669 * then it prints short signal names.
12670 * We are printing short names: */
12671 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012672 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012673 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012674 /* trap_ptr != trap only if we are in special-cased `trap` code.
12675 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012676 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012677 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012678 }
12679 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012680 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012681 if (trap_ptr != trap) {
12682 free(trap_ptr);
12683 trap_ptr = trap;
12684 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012685 */
Eric Andersencb57d552001-06-28 07:25:16 +000012686 return 0;
12687 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012688
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012689 action = NULL;
12690 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012691 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012692 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012693 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012694 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012695 if (signo < 0) {
12696 /* Mimic bash message exactly */
12697 ash_msg("%s: invalid signal specification", *ap);
12698 exitcode = 1;
12699 goto next;
12700 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012701 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012702 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012703 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012704 action = NULL;
12705 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012706 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012707 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012708 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012709 if (action)
12710 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012711 trap[signo] = action;
12712 if (signo != 0)
12713 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012714 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012715 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012716 ap++;
12717 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012718 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012719}
12720
Eric Andersenc470f442003-07-28 09:56:35 +000012721
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012722/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012723
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012724#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012725static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012726helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012727{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012728 unsigned col;
12729 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012730
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012731 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012732 "Built-in commands:\n"
12733 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012734 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012735 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012736 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012737 if (col > 60) {
12738 out1fmt("\n");
12739 col = 0;
12740 }
12741 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012742# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012743 {
12744 const char *a = applet_names;
12745 while (*a) {
12746 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12747 if (col > 60) {
12748 out1fmt("\n");
12749 col = 0;
12750 }
Ron Yorston2b919582016-04-08 11:57:20 +010012751 while (*a++ != '\0')
12752 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012753 }
12754 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012755# endif
Eric Andersenc470f442003-07-28 09:56:35 +000012756 out1fmt("\n\n");
12757 return EXIT_SUCCESS;
12758}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012759#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012760
Flemming Madsend96ffda2013-04-07 18:47:24 +020012761#if MAX_HISTORY
12762static int FAST_FUNC
12763historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12764{
12765 show_history(line_input_state);
12766 return EXIT_SUCCESS;
12767}
12768#endif
12769
Eric Andersencb57d552001-06-28 07:25:16 +000012770/*
Eric Andersencb57d552001-06-28 07:25:16 +000012771 * The export and readonly commands.
12772 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012773static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012774exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012775{
12776 struct var *vp;
12777 char *name;
12778 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012779 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012780 char opt;
12781 int flag;
12782 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012783
Denys Vlasenkod5275882012-10-01 13:41:17 +020012784 /* "readonly" in bash accepts, but ignores -n.
12785 * We do the same: it saves a conditional in nextopt's param.
12786 */
12787 flag_off = 0;
12788 while ((opt = nextopt("np")) != '\0') {
12789 if (opt == 'n')
12790 flag_off = VEXPORT;
12791 }
12792 flag = VEXPORT;
12793 if (argv[0][0] == 'r') {
12794 flag = VREADONLY;
12795 flag_off = 0; /* readonly ignores -n */
12796 }
12797 flag_off = ~flag_off;
12798
12799 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12800 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012801 aptr = argptr;
12802 name = *aptr;
12803 if (name) {
12804 do {
12805 p = strchr(name, '=');
12806 if (p != NULL) {
12807 p++;
12808 } else {
12809 vp = *findvar(hashvar(name), name);
12810 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012811 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012812 continue;
12813 }
Eric Andersencb57d552001-06-28 07:25:16 +000012814 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012815 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012816 } while ((name = *++aptr) != NULL);
12817 return 0;
12818 }
Eric Andersencb57d552001-06-28 07:25:16 +000012819 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012820
12821 /* No arguments. Show the list of exported or readonly vars.
12822 * -n is ignored.
12823 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012824 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012825 return 0;
12826}
12827
Eric Andersencb57d552001-06-28 07:25:16 +000012828/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012829 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012830 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012831static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012832unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012833{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012834 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012835
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012836 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012837 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012838 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012839}
12840
Eric Andersencb57d552001-06-28 07:25:16 +000012841/*
Eric Andersencb57d552001-06-28 07:25:16 +000012842 * The unset builtin command. We unset the function before we unset the
12843 * variable to allow a function to be unset when there is a readonly variable
12844 * with the same name.
12845 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012846static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012847unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012848{
12849 char **ap;
12850 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012851 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012852 int ret = 0;
12853
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012854 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012855 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012856 }
Eric Andersencb57d552001-06-28 07:25:16 +000012857
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012858 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012859 if (flag != 'f') {
12860 i = unsetvar(*ap);
12861 ret |= i;
12862 if (!(i & 2))
12863 continue;
12864 }
12865 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012866 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012867 }
Eric Andersenc470f442003-07-28 09:56:35 +000012868 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012869}
12870
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012871static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012872 ' ', offsetof(struct tms, tms_utime),
12873 '\n', offsetof(struct tms, tms_stime),
12874 ' ', offsetof(struct tms, tms_cutime),
12875 '\n', offsetof(struct tms, tms_cstime),
12876 0
12877};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012878static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012879timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012880{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012881 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012882 const unsigned char *p;
12883 struct tms buf;
12884
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012885 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012886 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012887
12888 p = timescmd_str;
12889 do {
12890 t = *(clock_t *)(((char *) &buf) + p[1]);
12891 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012892 t = t % clk_tck;
12893 out1fmt("%lum%lu.%03lus%c",
12894 s / 60, s % 60,
12895 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012896 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012897 p += 2;
12898 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012899
Eric Andersencb57d552001-06-28 07:25:16 +000012900 return 0;
12901}
12902
Mike Frysinger98c52642009-04-02 10:02:37 +000012903#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012904/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012905 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012906 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012907 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012908 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012909 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012910static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012911letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012912{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012913 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012914
Denis Vlasenko68404f12008-03-17 09:00:54 +000012915 argv++;
12916 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012917 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012918 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012919 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012920 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012921
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012922 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012923}
Eric Andersenc470f442003-07-28 09:56:35 +000012924#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012925
Eric Andersenc470f442003-07-28 09:56:35 +000012926/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012927 * The read builtin. Options:
12928 * -r Do not interpret '\' specially
12929 * -s Turn off echo (tty only)
12930 * -n NCHARS Read NCHARS max
12931 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12932 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12933 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012934 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012935 * TODO: bash also has:
12936 * -a ARRAY Read into array[0],[1],etc
12937 * -d DELIM End on DELIM char, not newline
12938 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012939 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012940static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012941readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012942{
Denys Vlasenko73067272010-01-12 22:11:24 +010012943 char *opt_n = NULL;
12944 char *opt_p = NULL;
12945 char *opt_t = NULL;
12946 char *opt_u = NULL;
12947 int read_flags = 0;
12948 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012949 int i;
12950
Denys Vlasenko73067272010-01-12 22:11:24 +010012951 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012952 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012953 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012954 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012955 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012956 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012957 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012958 break;
12959 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012960 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012961 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012962 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012963 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012964 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012965 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012966 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012967 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012968 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012969 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012970 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012971 default:
12972 break;
12973 }
Eric Andersenc470f442003-07-28 09:56:35 +000012974 }
Paul Fox02eb9342005-09-07 16:56:02 +000012975
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012976 /* "read -s" needs to save/restore termios, can't allow ^C
12977 * to jump out of it.
12978 */
12979 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012980 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010012981 argptr,
12982 bltinlookup("IFS"), /* can be NULL */
12983 read_flags,
12984 opt_n,
12985 opt_p,
12986 opt_t,
12987 opt_u
12988 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012989 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012990
Denys Vlasenko73067272010-01-12 22:11:24 +010012991 if ((uintptr_t)r > 1)
12992 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012993
Denys Vlasenko73067272010-01-12 22:11:24 +010012994 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012995}
12996
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012997static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020012998umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012999{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013000 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000013001
Eric Andersenc470f442003-07-28 09:56:35 +000013002 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000013003 int symbolic_mode = 0;
13004
13005 while (nextopt("S") != '\0') {
13006 symbolic_mode = 1;
13007 }
13008
Denis Vlasenkob012b102007-02-19 22:43:01 +000013009 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013010 mask = umask(0);
13011 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013012 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013013
Denys Vlasenko6283f982015-10-07 16:56:20 +020013014 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013015 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013016 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013017 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013018 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013019
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013020 i = 2;
13021 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013022 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013023 *p++ = permuser[i];
13024 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013025 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013026 if (!(mask & 0400)) *p++ = 'r';
13027 if (!(mask & 0200)) *p++ = 'w';
13028 if (!(mask & 0100)) *p++ = 'x';
13029 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013030 if (--i < 0)
13031 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013032 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013033 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013034 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013035 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013036 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013037 }
13038 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013039 char *modestr = *argptr;
13040 /* numeric umasks are taken as-is */
13041 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13042 if (!isdigit(modestr[0]))
13043 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013044 mask = bb_parse_mode(modestr, mask);
13045 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013046 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013047 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013048 if (!isdigit(modestr[0]))
13049 mask ^= 0777;
13050 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013051 }
13052 return 0;
13053}
13054
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013055static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013056ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013057{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013058 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013059}
13060
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013061/* ============ main() and helpers */
13062
13063/*
13064 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013065 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013066static void
13067exitshell(void)
13068{
13069 struct jmploc loc;
13070 char *p;
13071 int status;
13072
Denys Vlasenkobede2152011-09-04 16:12:33 +020013073#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13074 save_history(line_input_state);
13075#endif
13076
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013077 status = exitstatus;
13078 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13079 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013080 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013081/* dash bug: it just does _exit(exitstatus) here
13082 * but we have to do setjobctl(0) first!
13083 * (bug is still not fixed in dash-0.5.3 - if you run dash
13084 * under Midnight Commander, on exit from dash MC is backgrounded) */
13085 status = exitstatus;
13086 goto out;
13087 }
13088 exception_handler = &loc;
13089 p = trap[0];
13090 if (p) {
13091 trap[0] = NULL;
13092 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020013093 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013094 }
13095 flush_stdout_stderr();
13096 out:
13097 setjobctl(0);
13098 _exit(status);
13099 /* NOTREACHED */
13100}
13101
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013102static void
13103init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013104{
13105 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013106 /* we will never free this */
13107 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013108
13109 /* from trap.c: */
13110 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013111 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13112 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13113 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013114 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013115
13116 /* from var.c: */
13117 {
13118 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013119 const char *p;
13120 struct stat st1, st2;
13121
13122 initvar();
13123 for (envp = environ; envp && *envp; envp++) {
13124 if (strchr(*envp, '=')) {
13125 setvareq(*envp, VEXPORT|VTEXTFIXED);
13126 }
13127 }
13128
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013129 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013130#if ENABLE_ASH_BASH_COMPAT
13131 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013132 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013133 if (!lookupvar("HOSTNAME")) {
13134 struct utsname uts;
13135 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013136 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013137 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013138#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013139 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013140 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013141 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013142 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13143 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013144 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013145 }
13146 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013147 setpwd(p, 0);
13148 }
13149}
13150
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013151
13152//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013153//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013154//usage:#define ash_full_usage "\n\n"
13155//usage: "Unix shell interpreter"
13156
13157//usage:#if ENABLE_FEATURE_SH_IS_ASH
13158//usage:# define sh_trivial_usage ash_trivial_usage
13159//usage:# define sh_full_usage ash_full_usage
13160//usage:#endif
13161//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13162//usage:# define bash_trivial_usage ash_trivial_usage
13163//usage:# define bash_full_usage ash_full_usage
13164//usage:#endif
13165
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013166/*
13167 * Process the shell command line arguments.
13168 */
13169static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013170procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013171{
13172 int i;
13173 const char *xminusc;
13174 char **xargv;
13175
13176 xargv = argv;
13177 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013178 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013179 xargv++;
13180 for (i = 0; i < NOPTS; i++)
13181 optlist[i] = 2;
13182 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013183 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013184 /* it already printed err message */
13185 raise_exception(EXERROR);
13186 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013187 xargv = argptr;
13188 xminusc = minusc;
13189 if (*xargv == NULL) {
13190 if (xminusc)
13191 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13192 sflag = 1;
13193 }
13194 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13195 iflag = 1;
13196 if (mflag == 2)
13197 mflag = iflag;
13198 for (i = 0; i < NOPTS; i++)
13199 if (optlist[i] == 2)
13200 optlist[i] = 0;
13201#if DEBUG == 2
13202 debug = 1;
13203#endif
13204 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13205 if (xminusc) {
13206 minusc = *xargv++;
13207 if (*xargv)
13208 goto setarg0;
13209 } else if (!sflag) {
13210 setinputfile(*xargv, 0);
13211 setarg0:
13212 arg0 = *xargv++;
13213 commandname = arg0;
13214 }
13215
13216 shellparam.p = xargv;
13217#if ENABLE_ASH_GETOPTS
13218 shellparam.optind = 1;
13219 shellparam.optoff = -1;
13220#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013221 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013222 while (*xargv) {
13223 shellparam.nparam++;
13224 xargv++;
13225 }
13226 optschanged();
13227}
13228
13229/*
13230 * Read /etc/profile or .profile.
13231 */
13232static void
13233read_profile(const char *name)
13234{
13235 int skip;
13236
13237 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13238 return;
13239 skip = cmdloop(0);
13240 popfile();
13241 if (skip)
13242 exitshell();
13243}
13244
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013245/*
13246 * This routine is called when an error or an interrupt occurs in an
13247 * interactive shell and control is returned to the main command loop.
13248 */
13249static void
13250reset(void)
13251{
13252 /* from eval.c: */
13253 evalskip = 0;
13254 loopnest = 0;
13255 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013256 g_parsefile->left_in_buffer = 0;
13257 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013258 popallfiles();
13259 /* from parser.c: */
13260 tokpushback = 0;
13261 checkkwd = 0;
13262 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013263 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013264}
13265
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013266#if PROFILE
13267static short profile_buf[16384];
13268extern int etext();
13269#endif
13270
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013271/*
13272 * Main routine. We initialize things, parse the arguments, execute
13273 * profiles if we're a login shell, and then call cmdloop to execute
13274 * commands. The setjmp call sets up the location to jump to when an
13275 * exception occurs. When an exception occurs the variable "state"
13276 * is used to figure out how far we had gotten.
13277 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013278int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013279int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013280{
Mike Frysinger98c52642009-04-02 10:02:37 +000013281 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013282 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013283 struct jmploc jmploc;
13284 struct stackmark smark;
13285
Denis Vlasenko01631112007-12-16 17:20:38 +000013286 /* Initialize global data */
13287 INIT_G_misc();
13288 INIT_G_memstack();
13289 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013290#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013291 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013292#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013293 INIT_G_cmdtable();
13294
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013295#if PROFILE
13296 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13297#endif
13298
13299#if ENABLE_FEATURE_EDITING
13300 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13301#endif
13302 state = 0;
13303 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013304 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013305 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013306
13307 reset();
13308
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013309 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013310 if (e == EXERROR)
13311 exitstatus = 2;
13312 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013313 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013314 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013315 }
13316 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013317 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013318 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013319
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013320 popstackmark(&smark);
13321 FORCE_INT_ON; /* enable interrupts */
13322 if (s == 1)
13323 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013324 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013325 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013326 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013327 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013328 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013329 }
13330 exception_handler = &jmploc;
13331#if DEBUG
13332 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013333 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013334 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013335#endif
13336 rootpid = getpid();
13337
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013338 init();
13339 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013340 procargs(argv);
13341
Denys Vlasenko6088e132010-12-25 23:58:42 +010013342 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013343 isloginsh = 1;
13344 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013345 const char *hp;
13346
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013347 state = 1;
13348 read_profile("/etc/profile");
13349 state1:
13350 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013351 hp = lookupvar("HOME");
13352 if (hp) {
13353 hp = concat_path_file(hp, ".profile");
13354 read_profile(hp);
13355 free((char*)hp);
13356 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013357 }
13358 state2:
13359 state = 3;
13360 if (
13361#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013362 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013363#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013364 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013365 ) {
13366 shinit = lookupvar("ENV");
13367 if (shinit != NULL && *shinit != '\0') {
13368 read_profile(shinit);
13369 }
13370 }
13371 state3:
13372 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013373 if (minusc) {
13374 /* evalstring pushes parsefile stack.
13375 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013376 * is one of stacked source fds.
13377 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013378 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013379 // ^^ not necessary since now we special-case fd 0
13380 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013381 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013382 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013383
13384 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013385#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013386 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013387 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013388 if (!hp) {
13389 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013390 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013391 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013392 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013393 free((char*)hp);
13394 hp = lookupvar("HISTFILE");
13395 }
13396 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013397 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013398 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013399# if ENABLE_FEATURE_SH_HISTFILESIZE
13400 hp = lookupvar("HISTFILESIZE");
13401 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13402# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013403 }
13404#endif
13405 state4: /* XXX ??? - why isn't this before the "if" statement */
13406 cmdloop(1);
13407 }
13408#if PROFILE
13409 monitor(0);
13410#endif
13411#ifdef GPROF
13412 {
13413 extern void _mcleanup(void);
13414 _mcleanup();
13415 }
13416#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013417 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013418 exitshell();
13419 /* NOTREACHED */
13420}
13421
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013422
Eric Andersendf82f612001-06-28 07:46:40 +000013423/*-
13424 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013425 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013426 *
13427 * This code is derived from software contributed to Berkeley by
13428 * Kenneth Almquist.
13429 *
13430 * Redistribution and use in source and binary forms, with or without
13431 * modification, are permitted provided that the following conditions
13432 * are met:
13433 * 1. Redistributions of source code must retain the above copyright
13434 * notice, this list of conditions and the following disclaimer.
13435 * 2. Redistributions in binary form must reproduce the above copyright
13436 * notice, this list of conditions and the following disclaimer in the
13437 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013438 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013439 * may be used to endorse or promote products derived from this software
13440 * without specific prior written permission.
13441 *
13442 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13443 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13444 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13445 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13446 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13447 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13448 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13449 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13450 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13451 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13452 * SUCH DAMAGE.
13453 */