blob: d0c0a510cebf441612acdda4b55898a1bc25aefc [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 */
1171};
1172
1173struct parsefile {
1174 struct parsefile *prev; /* preceding file on stack */
1175 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001176 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001177 int left_in_line; /* number of chars left in this line */
1178 int left_in_buffer; /* number of chars left in this buffer past the line */
1179 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001180 char *buf; /* input buffer */
1181 struct strpush *strpush; /* for pushing strings at this level */
1182 struct strpush basestrpush; /* so pushing one is fast */
1183};
1184
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001185static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001186static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001187static int startlinno; /* line # where last token started */
1188static char *commandname; /* currently executing command */
1189static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001190static uint8_t exitstatus; /* exit status of last command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001191
1192
1193/* ============ Message printing */
1194
1195static void
1196ash_vmsg(const char *msg, va_list ap)
1197{
1198 fprintf(stderr, "%s: ", arg0);
1199 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001200 if (strcmp(arg0, commandname))
1201 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001202 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001203 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001204 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001205 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001206 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001207}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001208
1209/*
1210 * Exverror is called to raise the error exception. If the second argument
1211 * is not NULL then error prints an error message using printf style
1212 * formatting. It then raises the error exception.
1213 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001214static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001215static void
1216ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001217{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001218#if DEBUG
1219 if (msg) {
1220 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1221 TRACEV((msg, ap));
1222 TRACE(("\") pid=%d\n", getpid()));
1223 } else
1224 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1225 if (msg)
1226#endif
1227 ash_vmsg(msg, ap);
1228
1229 flush_stdout_stderr();
1230 raise_exception(cond);
1231 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001232}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001233
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001234static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001235static void
1236ash_msg_and_raise_error(const char *msg, ...)
1237{
1238 va_list ap;
1239
1240 va_start(ap, msg);
1241 ash_vmsg_and_raise(EXERROR, msg, ap);
1242 /* NOTREACHED */
1243 va_end(ap);
1244}
1245
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001246static void raise_error_syntax(const char *) NORETURN;
1247static void
1248raise_error_syntax(const char *msg)
1249{
1250 ash_msg_and_raise_error("syntax error: %s", msg);
1251 /* NOTREACHED */
1252}
1253
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001254static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001255static void
1256ash_msg_and_raise(int cond, const char *msg, ...)
1257{
1258 va_list ap;
1259
1260 va_start(ap, msg);
1261 ash_vmsg_and_raise(cond, msg, ap);
1262 /* NOTREACHED */
1263 va_end(ap);
1264}
1265
1266/*
1267 * error/warning routines for external builtins
1268 */
1269static void
1270ash_msg(const char *fmt, ...)
1271{
1272 va_list ap;
1273
1274 va_start(ap, fmt);
1275 ash_vmsg(fmt, ap);
1276 va_end(ap);
1277}
1278
1279/*
1280 * Return a string describing an error. The returned string may be a
1281 * pointer to a static buffer that will be overwritten on the next call.
1282 * Action describes the operation that got the error.
1283 */
1284static const char *
1285errmsg(int e, const char *em)
1286{
1287 if (e == ENOENT || e == ENOTDIR) {
1288 return em;
1289 }
1290 return strerror(e);
1291}
1292
1293
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001294/* ============ Memory allocation */
1295
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001296#if 0
1297/* I consider these wrappers nearly useless:
1298 * ok, they return you to nearest exception handler, but
1299 * how much memory do you leak in the process, making
1300 * memory starvation worse?
1301 */
1302static void *
1303ckrealloc(void * p, size_t nbytes)
1304{
1305 p = realloc(p, nbytes);
1306 if (!p)
1307 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1308 return p;
1309}
1310
1311static void *
1312ckmalloc(size_t nbytes)
1313{
1314 return ckrealloc(NULL, nbytes);
1315}
1316
1317static void *
1318ckzalloc(size_t nbytes)
1319{
1320 return memset(ckmalloc(nbytes), 0, nbytes);
1321}
1322
1323static char *
1324ckstrdup(const char *s)
1325{
1326 char *p = strdup(s);
1327 if (!p)
1328 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1329 return p;
1330}
1331#else
1332/* Using bbox equivalents. They exit if out of memory */
1333# define ckrealloc xrealloc
1334# define ckmalloc xmalloc
1335# define ckzalloc xzalloc
1336# define ckstrdup xstrdup
1337#endif
1338
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001339/*
1340 * It appears that grabstackstr() will barf with such alignments
1341 * because stalloc() will return a string allocated in a new stackblock.
1342 */
1343#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1344enum {
1345 /* Most machines require the value returned from malloc to be aligned
1346 * in some way. The following macro will get this right
1347 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001348 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001349 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001350 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001351};
1352
1353struct stack_block {
1354 struct stack_block *prev;
1355 char space[MINSIZE];
1356};
1357
1358struct stackmark {
1359 struct stack_block *stackp;
1360 char *stacknxt;
1361 size_t stacknleft;
1362 struct stackmark *marknext;
1363};
1364
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001365
Denis Vlasenko01631112007-12-16 17:20:38 +00001366struct globals_memstack {
1367 struct stack_block *g_stackp; // = &stackbase;
1368 struct stackmark *markp;
1369 char *g_stacknxt; // = stackbase.space;
1370 char *sstrend; // = stackbase.space + MINSIZE;
1371 size_t g_stacknleft; // = MINSIZE;
1372 int herefd; // = -1;
1373 struct stack_block stackbase;
1374};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001375extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1376#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001377#define g_stackp (G_memstack.g_stackp )
1378#define markp (G_memstack.markp )
1379#define g_stacknxt (G_memstack.g_stacknxt )
1380#define sstrend (G_memstack.sstrend )
1381#define g_stacknleft (G_memstack.g_stacknleft)
1382#define herefd (G_memstack.herefd )
1383#define stackbase (G_memstack.stackbase )
1384#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001385 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1386 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001387 g_stackp = &stackbase; \
1388 g_stacknxt = stackbase.space; \
1389 g_stacknleft = MINSIZE; \
1390 sstrend = stackbase.space + MINSIZE; \
1391 herefd = -1; \
1392} while (0)
1393
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001394
Denis Vlasenko01631112007-12-16 17:20:38 +00001395#define stackblock() ((void *)g_stacknxt)
1396#define stackblocksize() g_stacknleft
1397
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001398/*
1399 * Parse trees for commands are allocated in lifo order, so we use a stack
1400 * to make this more efficient, and also to avoid all sorts of exception
1401 * handling code to handle interrupts in the middle of a parse.
1402 *
1403 * The size 504 was chosen because the Ultrix malloc handles that size
1404 * well.
1405 */
1406static void *
1407stalloc(size_t nbytes)
1408{
1409 char *p;
1410 size_t aligned;
1411
1412 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001413 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001414 size_t len;
1415 size_t blocksize;
1416 struct stack_block *sp;
1417
1418 blocksize = aligned;
1419 if (blocksize < MINSIZE)
1420 blocksize = MINSIZE;
1421 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1422 if (len < blocksize)
1423 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1424 INT_OFF;
1425 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001426 sp->prev = g_stackp;
1427 g_stacknxt = sp->space;
1428 g_stacknleft = blocksize;
1429 sstrend = g_stacknxt + blocksize;
1430 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001431 INT_ON;
1432 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001433 p = g_stacknxt;
1434 g_stacknxt += aligned;
1435 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001436 return p;
1437}
1438
Denis Vlasenko597906c2008-02-20 16:38:54 +00001439static void *
1440stzalloc(size_t nbytes)
1441{
1442 return memset(stalloc(nbytes), 0, nbytes);
1443}
1444
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001445static void
1446stunalloc(void *p)
1447{
1448#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001449 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001450 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001451 abort();
1452 }
1453#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001454 g_stacknleft += g_stacknxt - (char *)p;
1455 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001456}
1457
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001458/*
1459 * Like strdup but works with the ash stack.
1460 */
1461static char *
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02001462sstrdup(const char *p)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001463{
1464 size_t len = strlen(p) + 1;
1465 return memcpy(stalloc(len), p, len);
1466}
1467
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001468static void
1469setstackmark(struct stackmark *mark)
1470{
Denis Vlasenko01631112007-12-16 17:20:38 +00001471 mark->stackp = g_stackp;
1472 mark->stacknxt = g_stacknxt;
1473 mark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001474 mark->marknext = markp;
1475 markp = mark;
1476}
1477
1478static void
1479popstackmark(struct stackmark *mark)
1480{
1481 struct stack_block *sp;
1482
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001483 if (!mark->stackp)
1484 return;
1485
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001486 INT_OFF;
1487 markp = mark->marknext;
Denis Vlasenko01631112007-12-16 17:20:38 +00001488 while (g_stackp != mark->stackp) {
1489 sp = g_stackp;
1490 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001491 free(sp);
1492 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001493 g_stacknxt = mark->stacknxt;
1494 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001495 sstrend = mark->stacknxt + mark->stacknleft;
1496 INT_ON;
1497}
1498
1499/*
1500 * When the parser reads in a string, it wants to stick the string on the
1501 * stack and only adjust the stack pointer when it knows how big the
1502 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1503 * of space on top of the stack and stackblocklen returns the length of
1504 * this block. Growstackblock will grow this space by at least one byte,
1505 * possibly moving it (like realloc). Grabstackblock actually allocates the
1506 * part of the block that has been used.
1507 */
1508static void
1509growstackblock(void)
1510{
1511 size_t newlen;
1512
Denis Vlasenko01631112007-12-16 17:20:38 +00001513 newlen = g_stacknleft * 2;
1514 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001515 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1516 if (newlen < 128)
1517 newlen += 128;
1518
Denis Vlasenko01631112007-12-16 17:20:38 +00001519 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001520 struct stack_block *oldstackp;
1521 struct stackmark *xmark;
1522 struct stack_block *sp;
1523 struct stack_block *prevstackp;
1524 size_t grosslen;
1525
1526 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001527 oldstackp = g_stackp;
1528 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001529 prevstackp = sp->prev;
1530 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1531 sp = ckrealloc(sp, grosslen);
1532 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001533 g_stackp = sp;
1534 g_stacknxt = sp->space;
1535 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001536 sstrend = sp->space + newlen;
1537
1538 /*
1539 * Stack marks pointing to the start of the old block
1540 * must be relocated to point to the new block
1541 */
1542 xmark = markp;
1543 while (xmark != NULL && xmark->stackp == oldstackp) {
Denis Vlasenko01631112007-12-16 17:20:38 +00001544 xmark->stackp = g_stackp;
1545 xmark->stacknxt = g_stacknxt;
1546 xmark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001547 xmark = xmark->marknext;
1548 }
1549 INT_ON;
1550 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001551 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001552 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001553 char *p = stalloc(newlen);
1554
1555 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001556 g_stacknxt = memcpy(p, oldspace, oldlen);
1557 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001558 }
1559}
1560
1561static void
1562grabstackblock(size_t len)
1563{
1564 len = SHELL_ALIGN(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001565 g_stacknxt += len;
1566 g_stacknleft -= len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001567}
1568
1569/*
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
2473 setstackmark(&smark);
2474 stalloc(stackblocksize());
2475#endif
2476 putprompt(expandstr(prompt));
2477#if ENABLE_ASH_EXPAND_PRMT
2478 popstackmark(&smark);
2479#endif
2480}
2481
2482
2483/* ============ The cd and pwd commands */
2484
2485#define CD_PHYSICAL 1
2486#define CD_PRINT 2
2487
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002488static int
2489cdopt(void)
2490{
2491 int flags = 0;
2492 int i, j;
2493
2494 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002495 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002496 if (i != j) {
2497 flags ^= CD_PHYSICAL;
2498 j = i;
2499 }
2500 }
2501
2502 return flags;
2503}
2504
2505/*
2506 * Update curdir (the name of the current directory) in response to a
2507 * cd command.
2508 */
2509static const char *
2510updatepwd(const char *dir)
2511{
2512 char *new;
2513 char *p;
2514 char *cdcomppath;
2515 const char *lim;
2516
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02002517 cdcomppath = sstrdup(dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002518 STARTSTACKSTR(new);
2519 if (*dir != '/') {
2520 if (curdir == nullstr)
2521 return 0;
2522 new = stack_putstr(curdir, new);
2523 }
2524 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002525 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002526 if (*dir != '/') {
2527 if (new[-1] != '/')
2528 USTPUTC('/', new);
2529 if (new > lim && *lim == '/')
2530 lim++;
2531 } else {
2532 USTPUTC('/', new);
2533 cdcomppath++;
2534 if (dir[1] == '/' && dir[2] != '/') {
2535 USTPUTC('/', new);
2536 cdcomppath++;
2537 lim++;
2538 }
2539 }
2540 p = strtok(cdcomppath, "/");
2541 while (p) {
2542 switch (*p) {
2543 case '.':
2544 if (p[1] == '.' && p[2] == '\0') {
2545 while (new > lim) {
2546 STUNPUTC(new);
2547 if (new[-1] == '/')
2548 break;
2549 }
2550 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002551 }
2552 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002553 break;
2554 /* fall through */
2555 default:
2556 new = stack_putstr(p, new);
2557 USTPUTC('/', new);
2558 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002559 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002560 }
2561 if (new > lim)
2562 STUNPUTC(new);
2563 *new = 0;
2564 return stackblock();
2565}
2566
2567/*
2568 * Find out what the current directory is. If we already know the current
2569 * directory, this routine returns immediately.
2570 */
2571static char *
2572getpwd(void)
2573{
Denis Vlasenko01631112007-12-16 17:20:38 +00002574 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002575 return dir ? dir : nullstr;
2576}
2577
2578static void
2579setpwd(const char *val, int setold)
2580{
2581 char *oldcur, *dir;
2582
2583 oldcur = dir = curdir;
2584
2585 if (setold) {
2586 setvar("OLDPWD", oldcur, VEXPORT);
2587 }
2588 INT_OFF;
2589 if (physdir != nullstr) {
2590 if (physdir != oldcur)
2591 free(physdir);
2592 physdir = nullstr;
2593 }
2594 if (oldcur == val || !val) {
2595 char *s = getpwd();
2596 physdir = s;
2597 if (!val)
2598 dir = s;
2599 } else
2600 dir = ckstrdup(val);
2601 if (oldcur != dir && oldcur != nullstr) {
2602 free(oldcur);
2603 }
2604 curdir = dir;
2605 INT_ON;
2606 setvar("PWD", dir, VEXPORT);
2607}
2608
2609static void hashcd(void);
2610
2611/*
2612 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2613 * know that the current directory has changed.
2614 */
2615static int
2616docd(const char *dest, int flags)
2617{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002618 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002619 int err;
2620
2621 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2622
2623 INT_OFF;
2624 if (!(flags & CD_PHYSICAL)) {
2625 dir = updatepwd(dest);
2626 if (dir)
2627 dest = dir;
2628 }
2629 err = chdir(dest);
2630 if (err)
2631 goto out;
2632 setpwd(dir, 1);
2633 hashcd();
2634 out:
2635 INT_ON;
2636 return err;
2637}
2638
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002639static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002640cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002641{
2642 const char *dest;
2643 const char *path;
2644 const char *p;
2645 char c;
2646 struct stat statb;
2647 int flags;
2648
2649 flags = cdopt();
2650 dest = *argptr;
2651 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002652 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002653 else if (LONE_DASH(dest)) {
2654 dest = bltinlookup("OLDPWD");
2655 flags |= CD_PRINT;
2656 }
2657 if (!dest)
2658 dest = nullstr;
2659 if (*dest == '/')
2660 goto step7;
2661 if (*dest == '.') {
2662 c = dest[1];
2663 dotdot:
2664 switch (c) {
2665 case '\0':
2666 case '/':
2667 goto step6;
2668 case '.':
2669 c = dest[2];
2670 if (c != '.')
2671 goto dotdot;
2672 }
2673 }
2674 if (!*dest)
2675 dest = ".";
2676 path = bltinlookup("CDPATH");
2677 if (!path) {
2678 step6:
2679 step7:
2680 p = dest;
2681 goto docd;
2682 }
2683 do {
2684 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002685 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002686 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2687 if (c && c != ':')
2688 flags |= CD_PRINT;
2689 docd:
2690 if (!docd(p, flags))
2691 goto out;
2692 break;
2693 }
2694 } while (path);
2695 ash_msg_and_raise_error("can't cd to %s", dest);
2696 /* NOTREACHED */
2697 out:
2698 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002699 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002700 return 0;
2701}
2702
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002703static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002704pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002705{
2706 int flags;
2707 const char *dir = curdir;
2708
2709 flags = cdopt();
2710 if (flags) {
2711 if (physdir == nullstr)
2712 setpwd(dir, 0);
2713 dir = physdir;
2714 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002715 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002716 return 0;
2717}
2718
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002719
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002720/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002721
Denis Vlasenko834dee72008-10-07 09:18:30 +00002722
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002723#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002724
Eric Andersenc470f442003-07-28 09:56:35 +00002725/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002726#define CWORD 0 /* character is nothing special */
2727#define CNL 1 /* newline character */
2728#define CBACK 2 /* a backslash character */
2729#define CSQUOTE 3 /* single quote */
2730#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002731#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002732#define CBQUOTE 6 /* backwards single quote */
2733#define CVAR 7 /* a dollar sign */
2734#define CENDVAR 8 /* a '}' character */
2735#define CLP 9 /* a left paren in arithmetic */
2736#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002737#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002738#define CCTL 12 /* like CWORD, except it must be escaped */
2739#define CSPCL 13 /* these terminate a word */
2740#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002741
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002742#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002743#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002744# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002745#endif
2746
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002747#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002748
Mike Frysinger98c52642009-04-02 10:02:37 +00002749#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002750# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002751#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002752# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002753#endif
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002754static const uint16_t S_I_T[] ALIGN2 = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002755#if ENABLE_ASH_ALIAS
2756 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2757#endif
2758 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2759 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2760 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2761 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2762 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2763 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2764 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2765 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2766 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2767 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2768 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002769#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002770 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2771 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2772 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2773#endif
2774#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002775};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002776/* Constants below must match table above */
2777enum {
2778#if ENABLE_ASH_ALIAS
2779 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2780#endif
2781 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2782 CNL_CNL_CNL_CNL , /* 2 */
2783 CWORD_CCTL_CCTL_CWORD , /* 3 */
2784 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2785 CVAR_CVAR_CWORD_CVAR , /* 5 */
2786 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2787 CSPCL_CWORD_CWORD_CLP , /* 7 */
2788 CSPCL_CWORD_CWORD_CRP , /* 8 */
2789 CBACK_CBACK_CCTL_CBACK , /* 9 */
2790 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2791 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2792 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2793 CWORD_CWORD_CWORD_CWORD , /* 13 */
2794 CCTL_CCTL_CCTL_CCTL , /* 14 */
2795};
Eric Andersen2870d962001-07-02 17:27:21 +00002796
Denys Vlasenkocd716832009-11-28 22:14:02 +01002797/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2798 * caller must ensure proper cast on it if c is *char_ptr!
2799 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002800/* Values for syntax param */
2801#define BASESYNTAX 0 /* not in quotes */
2802#define DQSYNTAX 1 /* in double quotes */
2803#define SQSYNTAX 2 /* in single quotes */
2804#define ARISYNTAX 3 /* in arithmetic */
2805#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002806
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002807#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002808
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002809static int
2810SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002811{
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002812 /* Used to also have '/' in this string: "\t\n !\"$&'()*-/:;<=>?[\\]`|}~" */
2813 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-:;<=>?[\\]`|}~";
2814 /*
2815 * This causes '/' to be prepended with CTLESC in dquoted string,
2816 * making "./file"* treated incorrectly because we feed
2817 * ".\/file*" string to glob(), confusing it (see expandmeta func).
2818 * The "homegrown" glob implementation is okay with that,
2819 * but glibc one isn't. With '/' always treated as CWORD,
2820 * both work fine.
2821 */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002822# if ENABLE_ASH_ALIAS
2823 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002824 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002825 7, 8, 3, 3,/*3,*/3, 1, 1, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002826 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2827 11, 3 /* "}~" */
2828 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002829# else
2830 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002831 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002832 6, 7, 2, 2,/*2,*/2, 0, 0, /* "()*-/:;<" */
Eric Andersenc470f442003-07-28 09:56:35 +00002833 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2834 10, 2 /* "}~" */
2835 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002836# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002837 const char *s;
2838 int indx;
2839
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002840 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002841 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002842# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002843 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002844 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002845 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002846# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002847 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002848 /* Cast is purely for paranoia here,
2849 * just in case someone passed signed char to us */
2850 if ((unsigned char)c >= CTL_FIRST
2851 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002852 ) {
2853 return CCTL;
2854 }
2855 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002856 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002857 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002858 indx = syntax_index_table[s - spec_symbls];
2859 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002860 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002861}
2862
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002863#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002864
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02002865static const uint8_t syntax_index_table[] ALIGN1 = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002866 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002867 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2877 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2878 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2895 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2896 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2897 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2898 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2899 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2900 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2901 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2902 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2903 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2904 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2905 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2906 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2907 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2908 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2909 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2910 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2912 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2913 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02002914/* "/" was CWORD_CCTL_CCTL_CWORD, see comment in SIT() function why this is changed: */
2915 /* 47 "/" */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenkocd716832009-11-28 22:14:02 +01002916 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2921 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2927 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2928 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2929 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2930 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2931 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2932 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2960 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2961 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2962 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2965 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2987 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2988 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2989 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2990 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2991 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2992 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2993 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2994 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2995 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2996 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2998 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2999 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
3000 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
3001 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
3002 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
3003 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
3004 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
3005 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3118 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3119 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3120 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3121 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3122 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3123 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003124 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003125# if ENABLE_ASH_ALIAS
3126 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3127# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003128};
3129
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003130# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003131
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003132#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003133
Eric Andersen2870d962001-07-02 17:27:21 +00003134
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003135/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003136
Denis Vlasenko131ae172007-02-18 13:00:19 +00003137#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003138
3139#define ALIASINUSE 1
3140#define ALIASDEAD 2
3141
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003142struct alias {
3143 struct alias *next;
3144 char *name;
3145 char *val;
3146 int flag;
3147};
3148
Denis Vlasenko01631112007-12-16 17:20:38 +00003149
3150static struct alias **atab; // [ATABSIZE];
3151#define INIT_G_alias() do { \
3152 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3153} while (0)
3154
Eric Andersen2870d962001-07-02 17:27:21 +00003155
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003156static struct alias **
3157__lookupalias(const char *name) {
3158 unsigned int hashval;
3159 struct alias **app;
3160 const char *p;
3161 unsigned int ch;
3162
3163 p = name;
3164
3165 ch = (unsigned char)*p;
3166 hashval = ch << 4;
3167 while (ch) {
3168 hashval += ch;
3169 ch = (unsigned char)*++p;
3170 }
3171 app = &atab[hashval % ATABSIZE];
3172
3173 for (; *app; app = &(*app)->next) {
3174 if (strcmp(name, (*app)->name) == 0) {
3175 break;
3176 }
3177 }
3178
3179 return app;
3180}
3181
3182static struct alias *
3183lookupalias(const char *name, int check)
3184{
3185 struct alias *ap = *__lookupalias(name);
3186
3187 if (check && ap && (ap->flag & ALIASINUSE))
3188 return NULL;
3189 return ap;
3190}
3191
3192static struct alias *
3193freealias(struct alias *ap)
3194{
3195 struct alias *next;
3196
3197 if (ap->flag & ALIASINUSE) {
3198 ap->flag |= ALIASDEAD;
3199 return ap;
3200 }
3201
3202 next = ap->next;
3203 free(ap->name);
3204 free(ap->val);
3205 free(ap);
3206 return next;
3207}
Eric Andersencb57d552001-06-28 07:25:16 +00003208
Eric Andersenc470f442003-07-28 09:56:35 +00003209static void
3210setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003211{
3212 struct alias *ap, **app;
3213
3214 app = __lookupalias(name);
3215 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003216 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003217 if (ap) {
3218 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003219 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003220 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003221 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003222 ap->flag &= ~ALIASDEAD;
3223 } else {
3224 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003225 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003226 ap->name = ckstrdup(name);
3227 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003228 /*ap->flag = 0; - ckzalloc did it */
3229 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003230 *app = ap;
3231 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003232 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003233}
3234
Eric Andersenc470f442003-07-28 09:56:35 +00003235static int
3236unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003237{
Eric Andersencb57d552001-06-28 07:25:16 +00003238 struct alias **app;
3239
3240 app = __lookupalias(name);
3241
3242 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003243 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003244 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003245 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003246 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003247 }
3248
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003249 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003250}
3251
Eric Andersenc470f442003-07-28 09:56:35 +00003252static void
3253rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003254{
Eric Andersencb57d552001-06-28 07:25:16 +00003255 struct alias *ap, **app;
3256 int i;
3257
Denis Vlasenkob012b102007-02-19 22:43:01 +00003258 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003259 for (i = 0; i < ATABSIZE; i++) {
3260 app = &atab[i];
3261 for (ap = *app; ap; ap = *app) {
3262 *app = freealias(*app);
3263 if (ap == *app) {
3264 app = &ap->next;
3265 }
3266 }
3267 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003268 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003269}
3270
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003271static void
3272printalias(const struct alias *ap)
3273{
3274 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3275}
3276
Eric Andersencb57d552001-06-28 07:25:16 +00003277/*
3278 * TODO - sort output
3279 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003280static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003281aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003282{
3283 char *n, *v;
3284 int ret = 0;
3285 struct alias *ap;
3286
Denis Vlasenko68404f12008-03-17 09:00:54 +00003287 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003288 int i;
3289
Denis Vlasenko68404f12008-03-17 09:00:54 +00003290 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003291 for (ap = atab[i]; ap; ap = ap->next) {
3292 printalias(ap);
3293 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003294 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003295 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003296 }
3297 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003298 v = strchr(n+1, '=');
3299 if (v == NULL) { /* n+1: funny ksh stuff */
3300 ap = *__lookupalias(n);
3301 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003302 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003303 ret = 1;
3304 } else
3305 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003306 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003307 *v++ = '\0';
3308 setalias(n, v);
3309 }
3310 }
3311
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003312 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003313}
3314
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003315static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003316unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003317{
3318 int i;
3319
3320 while ((i = nextopt("a")) != '\0') {
3321 if (i == 'a') {
3322 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003323 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003324 }
3325 }
3326 for (i = 0; *argptr; argptr++) {
3327 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003328 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003329 i = 1;
3330 }
3331 }
3332
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003333 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003334}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003335
Denis Vlasenko131ae172007-02-18 13:00:19 +00003336#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003337
Eric Andersenc470f442003-07-28 09:56:35 +00003338
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003339/* ============ jobs.c */
3340
3341/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003342#define FORK_FG 0
3343#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003344#define FORK_NOJOB 2
3345
3346/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003347#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3348#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3349#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003350#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003351
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003352/*
3353 * A job structure contains information about a job. A job is either a
3354 * single process or a set of processes contained in a pipeline. In the
3355 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3356 * array of pids.
3357 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003358struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003359 pid_t ps_pid; /* process id */
3360 int ps_status; /* last process status from wait() */
3361 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003362};
3363
3364struct job {
3365 struct procstat ps0; /* status of process */
3366 struct procstat *ps; /* status or processes when more than one */
3367#if JOBS
3368 int stopstatus; /* status of a stopped job */
3369#endif
3370 uint32_t
3371 nprocs: 16, /* number of processes */
3372 state: 8,
3373#define JOBRUNNING 0 /* at least one proc running */
3374#define JOBSTOPPED 1 /* all procs are stopped */
3375#define JOBDONE 2 /* all procs are completed */
3376#if JOBS
3377 sigint: 1, /* job was killed by SIGINT */
3378 jobctl: 1, /* job running under job control */
3379#endif
3380 waited: 1, /* true if this entry has been waited for */
3381 used: 1, /* true if this entry is in used */
3382 changed: 1; /* true if status has changed */
3383 struct job *prev_job; /* previous job */
3384};
3385
Denis Vlasenko68404f12008-03-17 09:00:54 +00003386static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003387static int forkshell(struct job *, union node *, int);
3388static int waitforjob(struct job *);
3389
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003390#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003391enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003392#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003393#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003394static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003395static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003396#endif
3397
3398/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003399 * Ignore a signal.
3400 */
3401static void
3402ignoresig(int signo)
3403{
3404 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3405 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3406 /* No, need to do it */
3407 signal(signo, SIG_IGN);
3408 }
3409 sigmode[signo - 1] = S_HARD_IGN;
3410}
3411
3412/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003413 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003414 */
3415static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003416signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003417{
3418 gotsig[signo - 1] = 1;
3419
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003420 if (signo == SIGINT && !trap[SIGINT]) {
3421 if (!suppress_int) {
3422 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003423 raise_interrupt(); /* does not return */
3424 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003425 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003426 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003427 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003428 }
3429}
3430
3431/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003432 * Set the signal handler for the specified signal. The routine figures
3433 * out what it should be set to.
3434 */
3435static void
3436setsignal(int signo)
3437{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003438 char *t;
3439 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003440 struct sigaction act;
3441
3442 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003443 new_act = S_DFL;
3444 if (t != NULL) { /* trap for this sig is set */
3445 new_act = S_CATCH;
3446 if (t[0] == '\0') /* trap is "": ignore this sig */
3447 new_act = S_IGN;
3448 }
3449
3450 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003451 switch (signo) {
3452 case SIGINT:
3453 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003454 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003455 break;
3456 case SIGQUIT:
3457#if DEBUG
3458 if (debug)
3459 break;
3460#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003461 /* man bash:
3462 * "In all cases, bash ignores SIGQUIT. Non-builtin
3463 * commands run by bash have signal handlers
3464 * set to the values inherited by the shell
3465 * from its parent". */
3466 new_act = S_IGN;
3467 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003468 case SIGTERM:
3469 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003470 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003471 break;
3472#if JOBS
3473 case SIGTSTP:
3474 case SIGTTOU:
3475 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003476 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003477 break;
3478#endif
3479 }
3480 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003481//TODO: if !rootshell, we reset SIGQUIT to DFL,
3482//whereas we have to restore it to what shell got on entry
3483//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003484
3485 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003486 cur_act = *t;
3487 if (cur_act == 0) {
3488 /* current setting is not yet known */
3489 if (sigaction(signo, NULL, &act)) {
3490 /* pretend it worked; maybe we should give a warning,
3491 * but other shells don't. We don't alter sigmode,
3492 * so we retry every time.
3493 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003494 return;
3495 }
3496 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003497 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003498 if (mflag
3499 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3500 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003501 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003502 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003503 }
3504 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003505 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003506 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003507
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003508 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003509 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003510 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003511 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003512 break;
3513 case S_IGN:
3514 act.sa_handler = SIG_IGN;
3515 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003516 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003517
3518 /* flags and mask matter only if !DFL and !IGN, but we do it
3519 * for all cases for more deterministic behavior:
3520 */
3521 act.sa_flags = 0;
3522 sigfillset(&act.sa_mask);
3523
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003524 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003525
3526 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527}
3528
3529/* mode flags for set_curjob */
3530#define CUR_DELETE 2
3531#define CUR_RUNNING 1
3532#define CUR_STOPPED 0
3533
3534/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003535#define DOWAIT_NONBLOCK WNOHANG
3536#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003537
3538#if JOBS
3539/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003540static int initialpgrp; //references:2
3541static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003542#endif
3543/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003544static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003545/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003546static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003547/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003548static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003549/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003550static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003551
3552static void
3553set_curjob(struct job *jp, unsigned mode)
3554{
3555 struct job *jp1;
3556 struct job **jpp, **curp;
3557
3558 /* first remove from list */
3559 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003560 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003561 jp1 = *jpp;
3562 if (jp1 == jp)
3563 break;
3564 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003565 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003566 *jpp = jp1->prev_job;
3567
3568 /* Then re-insert in correct position */
3569 jpp = curp;
3570 switch (mode) {
3571 default:
3572#if DEBUG
3573 abort();
3574#endif
3575 case CUR_DELETE:
3576 /* job being deleted */
3577 break;
3578 case CUR_RUNNING:
3579 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003580 * put after all stopped jobs.
3581 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003582 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003583 jp1 = *jpp;
3584#if JOBS
3585 if (!jp1 || jp1->state != JOBSTOPPED)
3586#endif
3587 break;
3588 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003589 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003590 /* FALLTHROUGH */
3591#if JOBS
3592 case CUR_STOPPED:
3593#endif
3594 /* newly stopped job - becomes curjob */
3595 jp->prev_job = *jpp;
3596 *jpp = jp;
3597 break;
3598 }
3599}
3600
3601#if JOBS || DEBUG
3602static int
3603jobno(const struct job *jp)
3604{
3605 return jp - jobtab + 1;
3606}
3607#endif
3608
3609/*
3610 * Convert a job name to a job structure.
3611 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003612#if !JOBS
3613#define getjob(name, getctl) getjob(name)
3614#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003615static struct job *
3616getjob(const char *name, int getctl)
3617{
3618 struct job *jp;
3619 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003620 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003621 unsigned num;
3622 int c;
3623 const char *p;
3624 char *(*match)(const char *, const char *);
3625
3626 jp = curjob;
3627 p = name;
3628 if (!p)
3629 goto currentjob;
3630
3631 if (*p != '%')
3632 goto err;
3633
3634 c = *++p;
3635 if (!c)
3636 goto currentjob;
3637
3638 if (!p[1]) {
3639 if (c == '+' || c == '%') {
3640 currentjob:
3641 err_msg = "No current job";
3642 goto check;
3643 }
3644 if (c == '-') {
3645 if (jp)
3646 jp = jp->prev_job;
3647 err_msg = "No previous job";
3648 check:
3649 if (!jp)
3650 goto err;
3651 goto gotit;
3652 }
3653 }
3654
3655 if (is_number(p)) {
3656 num = atoi(p);
Denys Vlasenko07f7ea72014-09-08 17:21:52 +02003657 if (num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003658 jp = jobtab + num - 1;
3659 if (jp->used)
3660 goto gotit;
3661 goto err;
3662 }
3663 }
3664
3665 match = prefix;
3666 if (*p == '?') {
3667 match = strstr;
3668 p++;
3669 }
3670
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003671 found = NULL;
3672 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003673 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003674 if (found)
3675 goto err;
3676 found = jp;
3677 err_msg = "%s: ambiguous";
3678 }
3679 jp = jp->prev_job;
3680 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003681 if (!found)
3682 goto err;
3683 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003684
3685 gotit:
3686#if JOBS
3687 err_msg = "job %s not created under job control";
3688 if (getctl && jp->jobctl == 0)
3689 goto err;
3690#endif
3691 return jp;
3692 err:
3693 ash_msg_and_raise_error(err_msg, name);
3694}
3695
3696/*
3697 * Mark a job structure as unused.
3698 */
3699static void
3700freejob(struct job *jp)
3701{
3702 struct procstat *ps;
3703 int i;
3704
3705 INT_OFF;
3706 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003707 if (ps->ps_cmd != nullstr)
3708 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003709 }
3710 if (jp->ps != &jp->ps0)
3711 free(jp->ps);
3712 jp->used = 0;
3713 set_curjob(jp, CUR_DELETE);
3714 INT_ON;
3715}
3716
3717#if JOBS
3718static void
3719xtcsetpgrp(int fd, pid_t pgrp)
3720{
3721 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003722 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003723}
3724
3725/*
3726 * Turn job control on and off.
3727 *
3728 * Note: This code assumes that the third arg to ioctl is a character
3729 * pointer, which is true on Berkeley systems but not System V. Since
3730 * System V doesn't have job control yet, this isn't a problem now.
3731 *
3732 * Called with interrupts off.
3733 */
3734static void
3735setjobctl(int on)
3736{
3737 int fd;
3738 int pgrp;
3739
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003740 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003741 return;
3742 if (on) {
3743 int ofd;
3744 ofd = fd = open(_PATH_TTY, O_RDWR);
3745 if (fd < 0) {
3746 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3747 * That sometimes helps to acquire controlling tty.
3748 * Obviously, a workaround for bugs when someone
3749 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003750 fd = 2;
3751 while (!isatty(fd))
3752 if (--fd < 0)
3753 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003754 }
3755 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003756 if (ofd >= 0)
3757 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003758 if (fd < 0)
3759 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003760 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003761 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003762 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003763 pgrp = tcgetpgrp(fd);
3764 if (pgrp < 0) {
3765 out:
3766 ash_msg("can't access tty; job control turned off");
3767 mflag = on = 0;
3768 goto close;
3769 }
3770 if (pgrp == getpgrp())
3771 break;
3772 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003773 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003774 initialpgrp = pgrp;
3775
3776 setsignal(SIGTSTP);
3777 setsignal(SIGTTOU);
3778 setsignal(SIGTTIN);
3779 pgrp = rootpid;
3780 setpgid(0, pgrp);
3781 xtcsetpgrp(fd, pgrp);
3782 } else {
3783 /* turning job control off */
3784 fd = ttyfd;
3785 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003786 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003787 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003788 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003789 setpgid(0, pgrp);
3790 setsignal(SIGTSTP);
3791 setsignal(SIGTTOU);
3792 setsignal(SIGTTIN);
3793 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003794 if (fd >= 0)
3795 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003796 fd = -1;
3797 }
3798 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003799 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003800}
3801
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003802static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003803killcmd(int argc, char **argv)
3804{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003805 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003806 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003807 do {
3808 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003809 /*
3810 * "kill %N" - job kill
3811 * Converting to pgrp / pid kill
3812 */
3813 struct job *jp;
3814 char *dst;
3815 int j, n;
3816
3817 jp = getjob(argv[i], 0);
3818 /*
3819 * In jobs started under job control, we signal
3820 * entire process group by kill -PGRP_ID.
3821 * This happens, f.e., in interactive shell.
3822 *
3823 * Otherwise, we signal each child via
3824 * kill PID1 PID2 PID3.
3825 * Testcases:
3826 * sh -c 'sleep 1|sleep 1 & kill %1'
3827 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3828 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3829 */
3830 n = jp->nprocs; /* can't be 0 (I hope) */
3831 if (jp->jobctl)
3832 n = 1;
3833 dst = alloca(n * sizeof(int)*4);
3834 argv[i] = dst;
3835 for (j = 0; j < n; j++) {
3836 struct procstat *ps = &jp->ps[j];
3837 /* Skip non-running and not-stopped members
3838 * (i.e. dead members) of the job
3839 */
3840 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3841 continue;
3842 /*
3843 * kill_main has matching code to expect
3844 * leading space. Needed to not confuse
3845 * negative pids with "kill -SIGNAL_NO" syntax
3846 */
3847 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3848 }
3849 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003850 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003851 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003852 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003853 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003854}
3855
3856static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003857showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003858{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003859 struct procstat *ps;
3860 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003861
Denys Vlasenko285ad152009-12-04 23:02:27 +01003862 psend = jp->ps + jp->nprocs;
3863 for (ps = jp->ps + 1; ps < psend; ps++)
3864 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003865 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003866 flush_stdout_stderr();
3867}
3868
3869
3870static int
3871restartjob(struct job *jp, int mode)
3872{
3873 struct procstat *ps;
3874 int i;
3875 int status;
3876 pid_t pgid;
3877
3878 INT_OFF;
3879 if (jp->state == JOBDONE)
3880 goto out;
3881 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003882 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003883 if (mode == FORK_FG)
3884 xtcsetpgrp(ttyfd, pgid);
3885 killpg(pgid, SIGCONT);
3886 ps = jp->ps;
3887 i = jp->nprocs;
3888 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003889 if (WIFSTOPPED(ps->ps_status)) {
3890 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003891 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003892 ps++;
3893 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003894 out:
3895 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3896 INT_ON;
3897 return status;
3898}
3899
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003900static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003901fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003902{
3903 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003904 int mode;
3905 int retval;
3906
3907 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3908 nextopt(nullstr);
3909 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003910 do {
3911 jp = getjob(*argv, 1);
3912 if (mode == FORK_BG) {
3913 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003914 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003915 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003916 out1str(jp->ps[0].ps_cmd);
3917 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003918 retval = restartjob(jp, mode);
3919 } while (*argv && *++argv);
3920 return retval;
3921}
3922#endif
3923
3924static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003925sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003926{
3927 int col;
3928 int st;
3929
3930 col = 0;
3931 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003932 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003933 st = WSTOPSIG(status);
3934 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003935 st = WTERMSIG(status);
3936 if (sigonly) {
3937 if (st == SIGINT || st == SIGPIPE)
3938 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003939 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003940 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003941 }
3942 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003943//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003944 col = fmtstr(s, 32, strsignal(st));
3945 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003946 strcpy(s + col, " (core dumped)");
3947 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003948 }
3949 } else if (!sigonly) {
3950 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003951 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003952 }
3953 out:
3954 return col;
3955}
3956
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003957static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003958dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003959{
3960 int pid;
3961 int status;
3962 struct job *jp;
3963 struct job *thisjob;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003964
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003965 TRACE(("dowait(0x%x) called\n", wait_flags));
3966
3967 /* Do a wait system call. If job control is compiled in, we accept
3968 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3969 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003970 if (doing_jobctl)
3971 wait_flags |= WUNTRACED;
3972 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003973 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3974 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003975 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003976 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003977
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003978 INT_OFF;
3979 thisjob = NULL;
3980 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003981 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003982 struct procstat *ps;
3983 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003984 if (jp->state == JOBDONE)
3985 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003986 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003987 ps = jp->ps;
3988 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003989 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003990 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003991 TRACE(("Job %d: changing status of proc %d "
3992 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003993 jobno(jp), pid, ps->ps_status, status));
3994 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003995 thisjob = jp;
3996 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003997 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003998 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003999#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004000 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004001 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004002 if (WIFSTOPPED(ps->ps_status)) {
4003 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004004 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004005 }
4006#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004007 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004008 if (!thisjob)
4009 continue;
4010
4011 /* Found the job where one of its processes changed its state.
4012 * Is there at least one live and running process in this job? */
4013 if (jobstate != JOBRUNNING) {
4014 /* No. All live processes in the job are stopped
4015 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4016 */
4017 thisjob->changed = 1;
4018 if (thisjob->state != jobstate) {
4019 TRACE(("Job %d: changing state from %d to %d\n",
4020 jobno(thisjob), thisjob->state, jobstate));
4021 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004022#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004023 if (jobstate == JOBSTOPPED)
4024 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004025#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004026 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004027 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004028 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004029 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004030 /* The process wasn't found in job list */
4031 if (JOBS && !WIFSTOPPED(status))
4032 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004033 out:
4034 INT_ON;
4035
4036 if (thisjob && thisjob == job) {
4037 char s[48 + 1];
4038 int len;
4039
Denys Vlasenko9c541002015-10-07 15:44:36 +02004040 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004041 if (len) {
4042 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004043 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004044 out2str(s);
4045 }
4046 }
4047 return pid;
4048}
4049
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004050static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004051blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004052{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004053 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004054 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004055 raise_exception(EXSIG);
4056 return pid;
4057}
4058
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004059#if JOBS
4060static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004061showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004062{
4063 struct procstat *ps;
4064 struct procstat *psend;
4065 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004066 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004067 char s[16 + 16 + 48];
4068 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004069
4070 ps = jp->ps;
4071
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004072 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004074 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004075 return;
4076 }
4077
4078 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004079 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004080
4081 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004082 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004083 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004084 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004085
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004086 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004087 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004088
4089 psend = ps + jp->nprocs;
4090
4091 if (jp->state == JOBRUNNING) {
4092 strcpy(s + col, "Running");
4093 col += sizeof("Running") - 1;
4094 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004095 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004096 if (jp->state == JOBSTOPPED)
4097 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004098 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004099 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004100 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004101
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004102 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4103 * or prints several "PID | <cmdN>" lines,
4104 * depending on SHOW_PIDS bit.
4105 * We do not print status of individual processes
4106 * between PID and <cmdN>. bash does it, but not very well:
4107 * first line shows overall job status, not process status,
4108 * making it impossible to know 1st process status.
4109 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004111 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004112 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004113 s[0] = '\0';
4114 col = 33;
4115 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004116 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004117 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004118 fprintf(out, "%s%*c%s%s",
4119 s,
4120 33 - col >= 0 ? 33 - col : 0, ' ',
4121 ps == jp->ps ? "" : "| ",
4122 ps->ps_cmd
4123 );
4124 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004125 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004126
4127 jp->changed = 0;
4128
4129 if (jp->state == JOBDONE) {
4130 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4131 freejob(jp);
4132 }
4133}
4134
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004135/*
4136 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4137 * statuses have changed since the last call to showjobs.
4138 */
4139static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004140showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004141{
4142 struct job *jp;
4143
Denys Vlasenko883cea42009-07-11 15:31:59 +02004144 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004145
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004146 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004147 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004148 continue;
4149
4150 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004151 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004152 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004153 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004154 }
4155}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004156
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004157static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004158jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004159{
4160 int mode, m;
4161
4162 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004163 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004164 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004165 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004166 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004167 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004168 }
4169
4170 argv = argptr;
4171 if (*argv) {
4172 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004173 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004174 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004175 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004176 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004177 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004178
4179 return 0;
4180}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004181#endif /* JOBS */
4182
Michael Abbott359da5e2009-12-04 23:03:29 +01004183/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004184static int
4185getstatus(struct job *job)
4186{
4187 int status;
4188 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004189 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004190
Michael Abbott359da5e2009-12-04 23:03:29 +01004191 /* Fetch last member's status */
4192 ps = job->ps + job->nprocs - 1;
4193 status = ps->ps_status;
4194 if (pipefail) {
4195 /* "set -o pipefail" mode: use last _nonzero_ status */
4196 while (status == 0 && --ps >= job->ps)
4197 status = ps->ps_status;
4198 }
4199
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004200 retval = WEXITSTATUS(status);
4201 if (!WIFEXITED(status)) {
4202#if JOBS
4203 retval = WSTOPSIG(status);
4204 if (!WIFSTOPPED(status))
4205#endif
4206 {
4207 /* XXX: limits number of signals */
4208 retval = WTERMSIG(status);
4209#if JOBS
4210 if (retval == SIGINT)
4211 job->sigint = 1;
4212#endif
4213 }
4214 retval += 128;
4215 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004216 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004217 jobno(job), job->nprocs, status, retval));
4218 return retval;
4219}
4220
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004221static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004222waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004223{
4224 struct job *job;
4225 int retval;
4226 struct job *jp;
4227
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004228 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004229 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004230
4231 nextopt(nullstr);
4232 retval = 0;
4233
4234 argv = argptr;
4235 if (!*argv) {
4236 /* wait for all jobs */
4237 for (;;) {
4238 jp = curjob;
4239 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004240 if (!jp) /* no running procs */
4241 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004242 if (jp->state == JOBRUNNING)
4243 break;
4244 jp->waited = 1;
4245 jp = jp->prev_job;
4246 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004247 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004248 /* man bash:
4249 * "When bash is waiting for an asynchronous command via
4250 * the wait builtin, the reception of a signal for which a trap
4251 * has been set will cause the wait builtin to return immediately
4252 * with an exit status greater than 128, immediately after which
4253 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004254 *
4255 * blocking_wait_with_raise_on_sig raises signal handlers
4256 * if it gets no pid (pid < 0). However,
4257 * if child sends us a signal *and immediately exits*,
4258 * blocking_wait_with_raise_on_sig gets pid > 0
4259 * and does not handle pending_sig. Check this case: */
4260 if (pending_sig)
4261 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004262 }
4263 }
4264
4265 retval = 127;
4266 do {
4267 if (**argv != '%') {
4268 pid_t pid = number(*argv);
4269 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004270 while (1) {
4271 if (!job)
4272 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004273 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004274 break;
4275 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004276 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004277 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004278 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004279 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004280 /* loop until process terminated or stopped */
4281 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004282 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004283 job->waited = 1;
4284 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004285 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004286 } while (*++argv);
4287
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004288 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004289 return retval;
4290}
4291
4292static struct job *
4293growjobtab(void)
4294{
4295 size_t len;
4296 ptrdiff_t offset;
4297 struct job *jp, *jq;
4298
4299 len = njobs * sizeof(*jp);
4300 jq = jobtab;
4301 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4302
4303 offset = (char *)jp - (char *)jq;
4304 if (offset) {
4305 /* Relocate pointers */
4306 size_t l = len;
4307
4308 jq = (struct job *)((char *)jq + l);
4309 while (l) {
4310 l -= sizeof(*jp);
4311 jq--;
4312#define joff(p) ((struct job *)((char *)(p) + l))
4313#define jmove(p) (p) = (void *)((char *)(p) + offset)
4314 if (joff(jp)->ps == &jq->ps0)
4315 jmove(joff(jp)->ps);
4316 if (joff(jp)->prev_job)
4317 jmove(joff(jp)->prev_job);
4318 }
4319 if (curjob)
4320 jmove(curjob);
4321#undef joff
4322#undef jmove
4323 }
4324
4325 njobs += 4;
4326 jobtab = jp;
4327 jp = (struct job *)((char *)jp + len);
4328 jq = jp + 3;
4329 do {
4330 jq->used = 0;
4331 } while (--jq >= jp);
4332 return jp;
4333}
4334
4335/*
4336 * Return a new job structure.
4337 * Called with interrupts off.
4338 */
4339static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004340makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004341{
4342 int i;
4343 struct job *jp;
4344
4345 for (i = njobs, jp = jobtab; ; jp++) {
4346 if (--i < 0) {
4347 jp = growjobtab();
4348 break;
4349 }
4350 if (jp->used == 0)
4351 break;
4352 if (jp->state != JOBDONE || !jp->waited)
4353 continue;
4354#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004355 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004356 continue;
4357#endif
4358 freejob(jp);
4359 break;
4360 }
4361 memset(jp, 0, sizeof(*jp));
4362#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004363 /* jp->jobctl is a bitfield.
4364 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004365 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004366 jp->jobctl = 1;
4367#endif
4368 jp->prev_job = curjob;
4369 curjob = jp;
4370 jp->used = 1;
4371 jp->ps = &jp->ps0;
4372 if (nprocs > 1) {
4373 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4374 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004375 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004376 jobno(jp)));
4377 return jp;
4378}
4379
4380#if JOBS
4381/*
4382 * Return a string identifying a command (to be printed by the
4383 * jobs command).
4384 */
4385static char *cmdnextc;
4386
4387static void
4388cmdputs(const char *s)
4389{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004390 static const char vstype[VSTYPE + 1][3] = {
4391 "", "}", "-", "+", "?", "=",
4392 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004393 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004394 };
4395
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004396 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004397 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004398 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004399 unsigned char c;
4400 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004401 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004402
Denys Vlasenko46a14772009-12-10 21:27:13 +01004403 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004404 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4405 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004406 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004407 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004408 switch (c) {
4409 case CTLESC:
4410 c = *p++;
4411 break;
4412 case CTLVAR:
4413 subtype = *p++;
4414 if ((subtype & VSTYPE) == VSLENGTH)
4415 str = "${#";
4416 else
4417 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004418 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004419 case CTLENDVAR:
4420 str = "\"}" + !(quoted & 1);
4421 quoted >>= 1;
4422 subtype = 0;
4423 goto dostr;
4424 case CTLBACKQ:
4425 str = "$(...)";
4426 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004427#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004428 case CTLARI:
4429 str = "$((";
4430 goto dostr;
4431 case CTLENDARI:
4432 str = "))";
4433 goto dostr;
4434#endif
4435 case CTLQUOTEMARK:
4436 quoted ^= 1;
4437 c = '"';
4438 break;
4439 case '=':
4440 if (subtype == 0)
4441 break;
4442 if ((subtype & VSTYPE) != VSNORMAL)
4443 quoted <<= 1;
4444 str = vstype[subtype & VSTYPE];
4445 if (subtype & VSNUL)
4446 c = ':';
4447 else
4448 goto checkstr;
4449 break;
4450 case '\'':
4451 case '\\':
4452 case '"':
4453 case '$':
4454 /* These can only happen inside quotes */
4455 cc[0] = c;
4456 str = cc;
4457 c = '\\';
4458 break;
4459 default:
4460 break;
4461 }
4462 USTPUTC(c, nextc);
4463 checkstr:
4464 if (!str)
4465 continue;
4466 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004467 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004468 USTPUTC(c, nextc);
4469 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004470 } /* while *p++ not NUL */
4471
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004472 if (quoted & 1) {
4473 USTPUTC('"', nextc);
4474 }
4475 *nextc = 0;
4476 cmdnextc = nextc;
4477}
4478
4479/* cmdtxt() and cmdlist() call each other */
4480static void cmdtxt(union node *n);
4481
4482static void
4483cmdlist(union node *np, int sep)
4484{
4485 for (; np; np = np->narg.next) {
4486 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004487 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004488 cmdtxt(np);
4489 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004490 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004491 }
4492}
4493
4494static void
4495cmdtxt(union node *n)
4496{
4497 union node *np;
4498 struct nodelist *lp;
4499 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004500
4501 if (!n)
4502 return;
4503 switch (n->type) {
4504 default:
4505#if DEBUG
4506 abort();
4507#endif
4508 case NPIPE:
4509 lp = n->npipe.cmdlist;
4510 for (;;) {
4511 cmdtxt(lp->n);
4512 lp = lp->next;
4513 if (!lp)
4514 break;
4515 cmdputs(" | ");
4516 }
4517 break;
4518 case NSEMI:
4519 p = "; ";
4520 goto binop;
4521 case NAND:
4522 p = " && ";
4523 goto binop;
4524 case NOR:
4525 p = " || ";
4526 binop:
4527 cmdtxt(n->nbinary.ch1);
4528 cmdputs(p);
4529 n = n->nbinary.ch2;
4530 goto donode;
4531 case NREDIR:
4532 case NBACKGND:
4533 n = n->nredir.n;
4534 goto donode;
4535 case NNOT:
4536 cmdputs("!");
4537 n = n->nnot.com;
4538 donode:
4539 cmdtxt(n);
4540 break;
4541 case NIF:
4542 cmdputs("if ");
4543 cmdtxt(n->nif.test);
4544 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004545 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004546 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004547 cmdputs("; else ");
4548 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004549 } else {
4550 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004551 }
4552 p = "; fi";
4553 goto dotail;
4554 case NSUBSHELL:
4555 cmdputs("(");
4556 n = n->nredir.n;
4557 p = ")";
4558 goto dotail;
4559 case NWHILE:
4560 p = "while ";
4561 goto until;
4562 case NUNTIL:
4563 p = "until ";
4564 until:
4565 cmdputs(p);
4566 cmdtxt(n->nbinary.ch1);
4567 n = n->nbinary.ch2;
4568 p = "; done";
4569 dodo:
4570 cmdputs("; do ");
4571 dotail:
4572 cmdtxt(n);
4573 goto dotail2;
4574 case NFOR:
4575 cmdputs("for ");
4576 cmdputs(n->nfor.var);
4577 cmdputs(" in ");
4578 cmdlist(n->nfor.args, 1);
4579 n = n->nfor.body;
4580 p = "; done";
4581 goto dodo;
4582 case NDEFUN:
4583 cmdputs(n->narg.text);
4584 p = "() { ... }";
4585 goto dotail2;
4586 case NCMD:
4587 cmdlist(n->ncmd.args, 1);
4588 cmdlist(n->ncmd.redirect, 0);
4589 break;
4590 case NARG:
4591 p = n->narg.text;
4592 dotail2:
4593 cmdputs(p);
4594 break;
4595 case NHERE:
4596 case NXHERE:
4597 p = "<<...";
4598 goto dotail2;
4599 case NCASE:
4600 cmdputs("case ");
4601 cmdputs(n->ncase.expr->narg.text);
4602 cmdputs(" in ");
4603 for (np = n->ncase.cases; np; np = np->nclist.next) {
4604 cmdtxt(np->nclist.pattern);
4605 cmdputs(") ");
4606 cmdtxt(np->nclist.body);
4607 cmdputs(";; ");
4608 }
4609 p = "esac";
4610 goto dotail2;
4611 case NTO:
4612 p = ">";
4613 goto redir;
4614 case NCLOBBER:
4615 p = ">|";
4616 goto redir;
4617 case NAPPEND:
4618 p = ">>";
4619 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004620#if ENABLE_ASH_BASH_COMPAT
4621 case NTO2:
4622#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004623 case NTOFD:
4624 p = ">&";
4625 goto redir;
4626 case NFROM:
4627 p = "<";
4628 goto redir;
4629 case NFROMFD:
4630 p = "<&";
4631 goto redir;
4632 case NFROMTO:
4633 p = "<>";
4634 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004635 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004636 cmdputs(p);
4637 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004638 cmdputs(utoa(n->ndup.dupfd));
4639 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004640 }
4641 n = n->nfile.fname;
4642 goto donode;
4643 }
4644}
4645
4646static char *
4647commandtext(union node *n)
4648{
4649 char *name;
4650
4651 STARTSTACKSTR(cmdnextc);
4652 cmdtxt(n);
4653 name = stackblock();
4654 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4655 name, cmdnextc, cmdnextc));
4656 return ckstrdup(name);
4657}
4658#endif /* JOBS */
4659
4660/*
4661 * Fork off a subshell. If we are doing job control, give the subshell its
4662 * own process group. Jp is a job structure that the job is to be added to.
4663 * N is the command that will be evaluated by the child. Both jp and n may
4664 * be NULL. The mode parameter can be one of the following:
4665 * FORK_FG - Fork off a foreground process.
4666 * FORK_BG - Fork off a background process.
4667 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4668 * process group even if job control is on.
4669 *
4670 * When job control is turned off, background processes have their standard
4671 * input redirected to /dev/null (except for the second and later processes
4672 * in a pipeline).
4673 *
4674 * Called with interrupts off.
4675 */
4676/*
4677 * Clear traps on a fork.
4678 */
4679static void
4680clear_traps(void)
4681{
4682 char **tp;
4683
4684 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004685 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004686 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004687 if (trap_ptr == trap)
4688 free(*tp);
4689 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004690 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004691 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004692 setsignal(tp - trap);
4693 INT_ON;
4694 }
4695 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004696 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004697}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004698
4699/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004700static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004701
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004702/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004703static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004704forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004705{
4706 int oldlvl;
4707
4708 TRACE(("Child shell %d\n", getpid()));
4709 oldlvl = shlvl;
4710 shlvl++;
4711
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004712 /* man bash: "Non-builtin commands run by bash have signal handlers
4713 * set to the values inherited by the shell from its parent".
4714 * Do we do it correctly? */
4715
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004716 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004717
4718 if (mode == FORK_NOJOB /* is it `xxx` ? */
4719 && n && n->type == NCMD /* is it single cmd? */
4720 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004721 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004722 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4723 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4724 ) {
4725 TRACE(("Trap hack\n"));
4726 /* Awful hack for `trap` or $(trap).
4727 *
4728 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4729 * contains an example where "trap" is executed in a subshell:
4730 *
4731 * save_traps=$(trap)
4732 * ...
4733 * eval "$save_traps"
4734 *
4735 * Standard does not say that "trap" in subshell shall print
4736 * parent shell's traps. It only says that its output
4737 * must have suitable form, but then, in the above example
4738 * (which is not supposed to be normative), it implies that.
4739 *
4740 * bash (and probably other shell) does implement it
4741 * (traps are reset to defaults, but "trap" still shows them),
4742 * but as a result, "trap" logic is hopelessly messed up:
4743 *
4744 * # trap
4745 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4746 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4747 * # true | trap <--- trap is in subshell - no output (ditto)
4748 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4749 * trap -- 'echo Ho' SIGWINCH
4750 * # echo `(trap)` <--- in subshell in subshell - output
4751 * trap -- 'echo Ho' SIGWINCH
4752 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4753 * trap -- 'echo Ho' SIGWINCH
4754 *
4755 * The rules when to forget and when to not forget traps
4756 * get really complex and nonsensical.
4757 *
4758 * Our solution: ONLY bare $(trap) or `trap` is special.
4759 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004760 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004761 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004762 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004763 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004764 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004765#if JOBS
4766 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004767 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004768 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004769 pid_t pgrp;
4770
4771 if (jp->nprocs == 0)
4772 pgrp = getpid();
4773 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004774 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004775 /* this can fail because we are doing it in the parent also */
4776 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004777 if (mode == FORK_FG)
4778 xtcsetpgrp(ttyfd, pgrp);
4779 setsignal(SIGTSTP);
4780 setsignal(SIGTTOU);
4781 } else
4782#endif
4783 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004784 /* man bash: "When job control is not in effect,
4785 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004786 ignoresig(SIGINT);
4787 ignoresig(SIGQUIT);
4788 if (jp->nprocs == 0) {
4789 close(0);
4790 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004791 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004792 }
4793 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004794 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004795 if (iflag) { /* why if iflag only? */
4796 setsignal(SIGINT);
4797 setsignal(SIGTERM);
4798 }
4799 /* man bash:
4800 * "In all cases, bash ignores SIGQUIT. Non-builtin
4801 * commands run by bash have signal handlers
4802 * set to the values inherited by the shell
4803 * from its parent".
4804 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004805 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004806 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004807#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004808 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004809 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004810 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004811 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004812 /* "jobs": we do not want to clear job list for it,
4813 * instead we remove only _its_ own_ job from job list.
4814 * This makes "jobs .... | cat" more useful.
4815 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004816 freejob(curjob);
4817 return;
4818 }
4819#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004820 for (jp = curjob; jp; jp = jp->prev_job)
4821 freejob(jp);
4822 jobless = 0;
4823}
4824
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004825/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004826#if !JOBS
4827#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4828#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004829static void
4830forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4831{
4832 TRACE(("In parent shell: child = %d\n", pid));
4833 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004834 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4835 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004836 jobless++;
4837 return;
4838 }
4839#if JOBS
4840 if (mode != FORK_NOJOB && jp->jobctl) {
4841 int pgrp;
4842
4843 if (jp->nprocs == 0)
4844 pgrp = pid;
4845 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004846 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004847 /* This can fail because we are doing it in the child also */
4848 setpgid(pid, pgrp);
4849 }
4850#endif
4851 if (mode == FORK_BG) {
4852 backgndpid = pid; /* set $! */
4853 set_curjob(jp, CUR_RUNNING);
4854 }
4855 if (jp) {
4856 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004857 ps->ps_pid = pid;
4858 ps->ps_status = -1;
4859 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004860#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004861 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004862 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004863#endif
4864 }
4865}
4866
4867static int
4868forkshell(struct job *jp, union node *n, int mode)
4869{
4870 int pid;
4871
4872 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4873 pid = fork();
4874 if (pid < 0) {
4875 TRACE(("Fork failed, errno=%d", errno));
4876 if (jp)
4877 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004878 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004879 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004880 if (pid == 0) {
4881 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004882 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004883 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004884 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004885 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004886 return pid;
4887}
4888
4889/*
4890 * Wait for job to finish.
4891 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004892 * Under job control we have the problem that while a child process
4893 * is running interrupts generated by the user are sent to the child
4894 * but not to the shell. This means that an infinite loop started by
4895 * an interactive user may be hard to kill. With job control turned off,
4896 * an interactive user may place an interactive program inside a loop.
4897 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004898 * these interrupts to also abort the loop. The approach we take here
4899 * is to have the shell ignore interrupt signals while waiting for a
4900 * foreground process to terminate, and then send itself an interrupt
4901 * signal if the child process was terminated by an interrupt signal.
4902 * Unfortunately, some programs want to do a bit of cleanup and then
4903 * exit on interrupt; unless these processes terminate themselves by
4904 * sending a signal to themselves (instead of calling exit) they will
4905 * confuse this approach.
4906 *
4907 * Called with interrupts off.
4908 */
4909static int
4910waitforjob(struct job *jp)
4911{
4912 int st;
4913
4914 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004915
4916 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004917 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004918 /* In non-interactive shells, we _can_ get
4919 * a keyboard signal here and be EINTRed,
4920 * but we just loop back, waiting for command to complete.
4921 *
4922 * man bash:
4923 * "If bash is waiting for a command to complete and receives
4924 * a signal for which a trap has been set, the trap
4925 * will not be executed until the command completes."
4926 *
4927 * Reality is that even if trap is not set, bash
4928 * will not act on the signal until command completes.
4929 * Try this. sleep5intoff.c:
4930 * #include <signal.h>
4931 * #include <unistd.h>
4932 * int main() {
4933 * sigset_t set;
4934 * sigemptyset(&set);
4935 * sigaddset(&set, SIGINT);
4936 * sigaddset(&set, SIGQUIT);
4937 * sigprocmask(SIG_BLOCK, &set, NULL);
4938 * sleep(5);
4939 * return 0;
4940 * }
4941 * $ bash -c './sleep5intoff; echo hi'
4942 * ^C^C^C^C <--- pressing ^C once a second
4943 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004944 * $ bash -c './sleep5intoff; echo hi'
4945 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4946 * $ _
4947 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004948 dowait(DOWAIT_BLOCK, jp);
4949 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004950 INT_ON;
4951
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004952 st = getstatus(jp);
4953#if JOBS
4954 if (jp->jobctl) {
4955 xtcsetpgrp(ttyfd, rootpid);
4956 /*
4957 * This is truly gross.
4958 * If we're doing job control, then we did a TIOCSPGRP which
4959 * caused us (the shell) to no longer be in the controlling
4960 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4961 * intuit from the subprocess exit status whether a SIGINT
4962 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4963 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004964 if (jp->sigint) /* TODO: do the same with all signals */
4965 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004966 }
4967 if (jp->state == JOBDONE)
4968#endif
4969 freejob(jp);
4970 return st;
4971}
4972
4973/*
4974 * return 1 if there are stopped jobs, otherwise 0
4975 */
4976static int
4977stoppedjobs(void)
4978{
4979 struct job *jp;
4980 int retval;
4981
4982 retval = 0;
4983 if (job_warning)
4984 goto out;
4985 jp = curjob;
4986 if (jp && jp->state == JOBSTOPPED) {
4987 out2str("You have stopped jobs.\n");
4988 job_warning = 2;
4989 retval++;
4990 }
4991 out:
4992 return retval;
4993}
4994
4995
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004996/* ============ redir.c
4997 *
4998 * Code for dealing with input/output redirection.
4999 */
5000
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005001#undef EMPTY
5002#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005003#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005004#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005005
5006/*
5007 * Open a file in noclobber mode.
5008 * The code was copied from bash.
5009 */
5010static int
5011noclobberopen(const char *fname)
5012{
5013 int r, fd;
5014 struct stat finfo, finfo2;
5015
5016 /*
5017 * If the file exists and is a regular file, return an error
5018 * immediately.
5019 */
5020 r = stat(fname, &finfo);
5021 if (r == 0 && S_ISREG(finfo.st_mode)) {
5022 errno = EEXIST;
5023 return -1;
5024 }
5025
5026 /*
5027 * If the file was not present (r != 0), make sure we open it
5028 * exclusively so that if it is created before we open it, our open
5029 * will fail. Make sure that we do not truncate an existing file.
5030 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5031 * file was not a regular file, we leave O_EXCL off.
5032 */
5033 if (r != 0)
5034 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5035 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5036
5037 /* If the open failed, return the file descriptor right away. */
5038 if (fd < 0)
5039 return fd;
5040
5041 /*
5042 * OK, the open succeeded, but the file may have been changed from a
5043 * non-regular file to a regular file between the stat and the open.
5044 * We are assuming that the O_EXCL open handles the case where FILENAME
5045 * did not exist and is symlinked to an existing file between the stat
5046 * and open.
5047 */
5048
5049 /*
5050 * If we can open it and fstat the file descriptor, and neither check
5051 * revealed that it was a regular file, and the file has not been
5052 * replaced, return the file descriptor.
5053 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005054 if (fstat(fd, &finfo2) == 0
5055 && !S_ISREG(finfo2.st_mode)
5056 && finfo.st_dev == finfo2.st_dev
5057 && finfo.st_ino == finfo2.st_ino
5058 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005059 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005060 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005061
5062 /* The file has been replaced. badness. */
5063 close(fd);
5064 errno = EEXIST;
5065 return -1;
5066}
5067
5068/*
5069 * Handle here documents. Normally we fork off a process to write the
5070 * data to a pipe. If the document is short, we can stuff the data in
5071 * the pipe without forking.
5072 */
5073/* openhere needs this forward reference */
5074static void expandhere(union node *arg, int fd);
5075static int
5076openhere(union node *redir)
5077{
5078 int pip[2];
5079 size_t len = 0;
5080
5081 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005082 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005083 if (redir->type == NHERE) {
5084 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005085 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005086 full_write(pip[1], redir->nhere.doc->narg.text, len);
5087 goto out;
5088 }
5089 }
5090 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005091 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005092 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005093 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5094 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5095 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5096 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005097 signal(SIGPIPE, SIG_DFL);
5098 if (redir->type == NHERE)
5099 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005100 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005101 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005102 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005103 }
5104 out:
5105 close(pip[1]);
5106 return pip[0];
5107}
5108
5109static int
5110openredirect(union node *redir)
5111{
5112 char *fname;
5113 int f;
5114
5115 switch (redir->nfile.type) {
Denys Vlasenko557482c2016-09-25 21:24:04 +02005116/* Can't happen, our single caller does this itself */
5117// case NTOFD:
5118// case NFROMFD:
5119// return -1;
5120 case NHERE:
5121 case NXHERE:
5122 return openhere(redir);
5123 }
5124
5125 /* For N[X]HERE, reading redir->nfile.expfname would touch beyond
5126 * allocated space. Do it only when we know it is safe.
5127 */
5128 fname = redir->nfile.expfname;
5129
5130 switch (redir->nfile.type) {
5131 default:
5132#if DEBUG
5133 abort();
5134#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005135 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005136 f = open(fname, O_RDONLY);
5137 if (f < 0)
5138 goto eopen;
5139 break;
5140 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005141 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005142 if (f < 0)
5143 goto ecreate;
5144 break;
5145 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005146#if ENABLE_ASH_BASH_COMPAT
5147 case NTO2:
5148#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005149 /* Take care of noclobber mode. */
5150 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005151 f = noclobberopen(fname);
5152 if (f < 0)
5153 goto ecreate;
5154 break;
5155 }
5156 /* FALLTHROUGH */
5157 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005158 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5159 if (f < 0)
5160 goto ecreate;
5161 break;
5162 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005163 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5164 if (f < 0)
5165 goto ecreate;
5166 break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005167 }
5168
5169 return f;
5170 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005171 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005172 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005173 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005174}
5175
5176/*
5177 * Copy a file descriptor to be >= to. Returns -1
5178 * if the source file descriptor is closed, EMPTY if there are no unused
5179 * file descriptors left.
5180 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005181/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5182 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005183enum {
5184 COPYFD_EXACT = (int)~(INT_MAX),
5185 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5186};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005187static int
5188copyfd(int from, int to)
5189{
5190 int newfd;
5191
Denis Vlasenko5a867312008-07-24 19:46:38 +00005192 if (to & COPYFD_EXACT) {
5193 to &= ~COPYFD_EXACT;
5194 /*if (from != to)*/
5195 newfd = dup2(from, to);
5196 } else {
5197 newfd = fcntl(from, F_DUPFD, to);
5198 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005199 if (newfd < 0) {
5200 if (errno == EMFILE)
5201 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005202 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005203 ash_msg_and_raise_error("%d: %m", from);
5204 }
5205 return newfd;
5206}
5207
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005208/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005209struct two_fd_t {
5210 int orig, copy;
5211};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005212struct redirtab {
5213 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005214 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005215 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005216 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005217};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005218#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005219
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005220static int need_to_remember(struct redirtab *rp, int fd)
5221{
5222 int i;
5223
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005224 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005225 return 0;
5226
5227 for (i = 0; i < rp->pair_count; i++) {
5228 if (rp->two_fd[i].orig == fd) {
5229 /* already remembered */
5230 return 0;
5231 }
5232 }
5233 return 1;
5234}
5235
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005236/* "hidden" fd is a fd used to read scripts, or a copy of such */
5237static int is_hidden_fd(struct redirtab *rp, int fd)
5238{
5239 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005240 struct parsefile *pf;
5241
5242 if (fd == -1)
5243 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005244 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005245 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005246 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005247 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005248 * $ ash # running ash interactively
5249 * $ . ./script.sh
5250 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005251 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005252 * it's still ok to use it: "read" builtin uses it,
5253 * why should we cripple "exec" builtin?
5254 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005255 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005256 return 1;
5257 }
5258 pf = pf->prev;
5259 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005260
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005261 if (!rp)
5262 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005263 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005264 fd |= COPYFD_RESTORE;
5265 for (i = 0; i < rp->pair_count; i++) {
5266 if (rp->two_fd[i].copy == fd) {
5267 return 1;
5268 }
5269 }
5270 return 0;
5271}
5272
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005273/*
5274 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5275 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005276 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005277 */
5278/* flags passed to redirect */
5279#define REDIR_PUSH 01 /* save previous values of file descriptors */
5280#define REDIR_SAVEFD2 03 /* set preverrout */
5281static void
5282redirect(union node *redir, int flags)
5283{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005284 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005285 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005286 int i;
5287 int fd;
5288 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005289 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005290
Denis Vlasenko01631112007-12-16 17:20:38 +00005291 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005292 if (!redir) {
5293 return;
5294 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005295
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005296 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005297 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005298 INT_OFF;
5299 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005300 union node *tmp = redir;
5301 do {
5302 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005303#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005304 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005305 sv_pos++;
5306#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005307 tmp = tmp->nfile.next;
5308 } while (tmp);
5309 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005310 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005311 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005312 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005313 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005314 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005315 while (sv_pos > 0) {
5316 sv_pos--;
5317 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5318 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005319 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005320
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005321 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005322 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005323 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005324 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005325 right_fd = redir->ndup.dupfd;
5326 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005327 /* redirect from/to same file descriptor? */
5328 if (right_fd == fd)
5329 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005330 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005331 if (is_hidden_fd(sv, right_fd)) {
5332 errno = EBADF; /* as if it is closed */
5333 ash_msg_and_raise_error("%d: %m", right_fd);
5334 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005335 newfd = -1;
5336 } else {
5337 newfd = openredirect(redir); /* always >= 0 */
5338 if (fd == newfd) {
5339 /* Descriptor wasn't open before redirect.
5340 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005341 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005342 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005343 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005344 continue;
5345 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005346 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005347#if ENABLE_ASH_BASH_COMPAT
5348 redirect_more:
5349#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005350 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005351 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005352 /* Careful to not accidentally "save"
5353 * to the same fd as right side fd in N>&M */
5354 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5355 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005356/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5357 * are closed in popredir() in the child, preventing them from leaking
5358 * into child. (popredir() also cleans up the mess in case of failures)
5359 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005360 if (i == -1) {
5361 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005362 if (i != EBADF) {
5363 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005364 if (newfd >= 0)
5365 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005366 errno = i;
5367 ash_msg_and_raise_error("%d: %m", fd);
5368 /* NOTREACHED */
5369 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005370 /* EBADF: it is not open - good, remember to close it */
5371 remember_to_close:
5372 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005373 } else { /* fd is open, save its copy */
5374 /* "exec fd>&-" should not close fds
5375 * which point to script file(s).
5376 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005377 if (is_hidden_fd(sv, fd))
5378 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005379 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005380 if (fd == 2)
5381 copied_fd2 = i;
5382 sv->two_fd[sv_pos].orig = fd;
5383 sv->two_fd[sv_pos].copy = i;
5384 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005385 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005386 if (newfd < 0) {
5387 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005388 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005389 /* Don't want to trigger debugging */
5390 if (fd != -1)
5391 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005392 } else {
5393 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005394 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005395 } else if (fd != newfd) { /* move newfd to fd */
5396 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005397#if ENABLE_ASH_BASH_COMPAT
5398 if (!(redir->nfile.type == NTO2 && fd == 2))
5399#endif
5400 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005401 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005402#if ENABLE_ASH_BASH_COMPAT
5403 if (redir->nfile.type == NTO2 && fd == 1) {
5404 /* We already redirected it to fd 1, now copy it to 2 */
5405 newfd = 1;
5406 fd = 2;
5407 goto redirect_more;
5408 }
5409#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005410 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005411
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005412 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005413 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5414 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005415}
5416
5417/*
5418 * Undo the effects of the last redirection.
5419 */
5420static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005421popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005422{
5423 struct redirtab *rp;
5424 int i;
5425
Ron Yorston95650a82015-10-30 19:07:37 +00005426 if (--g_nullredirs >= 0 || redirlist == NULL)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005427 return;
5428 INT_OFF;
5429 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005430 for (i = 0; i < rp->pair_count; i++) {
5431 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005432 int copy = rp->two_fd[i].copy;
5433 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005434 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005435 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005436 continue;
5437 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005438 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005439 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005440 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005441 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005442 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005443 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005444 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005445 }
5446 }
5447 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005448 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005449 free(rp);
5450 INT_ON;
5451}
5452
5453/*
5454 * Undo all redirections. Called on error or interrupt.
5455 */
5456
5457/*
5458 * Discard all saved file descriptors.
5459 */
5460static void
5461clearredir(int drop)
5462{
5463 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005464 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005465 if (!redirlist)
5466 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005467 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005468 }
5469}
5470
5471static int
5472redirectsafe(union node *redir, int flags)
5473{
5474 int err;
5475 volatile int saveint;
5476 struct jmploc *volatile savehandler = exception_handler;
5477 struct jmploc jmploc;
5478
5479 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005480 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5481 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005482 if (!err) {
5483 exception_handler = &jmploc;
5484 redirect(redir, flags);
5485 }
5486 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005487 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005488 longjmp(exception_handler->loc, 1);
5489 RESTORE_INT(saveint);
5490 return err;
5491}
5492
5493
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005494/* ============ Routines to expand arguments to commands
5495 *
5496 * We have to deal with backquotes, shell variables, and file metacharacters.
5497 */
5498
Mike Frysinger98c52642009-04-02 10:02:37 +00005499#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005500static arith_t
5501ash_arith(const char *s)
5502{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005503 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005504 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005505
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005506 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005507 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005508 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005509
5510 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005511 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005512 if (math_state.errmsg)
5513 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005514 INT_ON;
5515
5516 return result;
5517}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005518#endif
5519
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005520/*
5521 * expandarg flags
5522 */
5523#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5524#define EXP_TILDE 0x2 /* do normal tilde expansion */
5525#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5526#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5527#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005528#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005529#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5530#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005531#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005532/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005533 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005534 */
5535#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5536#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005537#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5538#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005539#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005540
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005541/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005542#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005543/* Do not skip NUL characters. */
5544#define QUOTES_KEEPNUL EXP_TILDE
5545
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005546/*
5547 * Structure specifying which parts of the string should be searched
5548 * for IFS characters.
5549 */
5550struct ifsregion {
5551 struct ifsregion *next; /* next region in list */
5552 int begoff; /* offset of start of region */
5553 int endoff; /* offset of end of region */
5554 int nulonly; /* search for nul bytes only */
5555};
5556
5557struct arglist {
5558 struct strlist *list;
5559 struct strlist **lastp;
5560};
5561
5562/* output of current string */
5563static char *expdest;
5564/* list of back quote expressions */
5565static struct nodelist *argbackq;
5566/* first struct in list of ifs regions */
5567static struct ifsregion ifsfirst;
5568/* last struct in list */
5569static struct ifsregion *ifslastp;
5570/* holds expanded arg list */
5571static struct arglist exparg;
5572
5573/*
5574 * Our own itoa().
5575 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005576#if !ENABLE_SH_MATH_SUPPORT
5577/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5578typedef long arith_t;
5579# define ARITH_FMT "%ld"
5580#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005581static int
5582cvtnum(arith_t num)
5583{
5584 int len;
5585
Denys Vlasenko9c541002015-10-07 15:44:36 +02005586 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5587 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005588 STADJUST(len, expdest);
5589 return len;
5590}
5591
5592static size_t
5593esclen(const char *start, const char *p)
5594{
5595 size_t esc = 0;
5596
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005597 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005598 esc++;
5599 }
5600 return esc;
5601}
5602
5603/*
5604 * Remove any CTLESC characters from a string.
5605 */
5606static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005607rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005608{
Ron Yorston417622c2015-05-18 09:59:14 +02005609 static const char qchars[] ALIGN1 = {
5610 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005611
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005612 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005613 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005614 unsigned protect_against_glob;
5615 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005616 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005617
Ron Yorston417622c2015-05-18 09:59:14 +02005618 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005619 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005620 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005621
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005622 q = p;
5623 r = str;
5624 if (flag & RMESCAPE_ALLOC) {
5625 size_t len = p - str;
5626 size_t fulllen = len + strlen(p) + 1;
5627
5628 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005629 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005630 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005631 /* p and str may be invalidated by makestrspace */
5632 str = (char *)stackblock() + strloc;
5633 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005634 } else if (flag & RMESCAPE_HEAP) {
5635 r = ckmalloc(fulllen);
5636 } else {
5637 r = stalloc(fulllen);
5638 }
5639 q = r;
5640 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005641 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005642 }
5643 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005644
Ron Yorston549deab2015-05-18 09:57:51 +02005645 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005646 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005647 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005648 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005649 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005650// Note: both inquotes and protect_against_glob only affect whether
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005651 inquotes = ~inquotes;
5652 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005653 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005654 continue;
5655 }
Ron Yorston549deab2015-05-18 09:57:51 +02005656 if ((unsigned char)*p == CTLESC) {
5657 p++;
Denys Vlasenko13f20912016-09-25 20:54:25 +02005658#if DEBUG
5659 if (*p == '\0')
5660 ash_msg_and_raise_error("CTLESC at EOL (shouldn't happen)");
5661#endif
Ron Yorston549deab2015-05-18 09:57:51 +02005662 if (protect_against_glob) {
5663 *q++ = '\\';
5664 }
5665 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005666 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005667 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005668 goto copy;
5669 }
Ron Yorston417622c2015-05-18 09:59:14 +02005670#if ENABLE_ASH_BASH_COMPAT
5671 else if (*p == '/' && slash) {
5672 /* stop handling globbing and mark location of slash */
5673 globbing = slash = 0;
5674 *p = CTLESC;
5675 }
5676#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005677 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005678 copy:
5679 *q++ = *p++;
5680 }
5681 *q = '\0';
5682 if (flag & RMESCAPE_GROW) {
5683 expdest = r;
5684 STADJUST(q - r + 1, expdest);
5685 }
5686 return r;
5687}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005688#define pmatch(a, b) !fnmatch((a), (b), 0)
5689
5690/*
5691 * Prepare a pattern for a expmeta (internal glob(3)) call.
5692 *
5693 * Returns an stalloced string.
5694 */
5695static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005696preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005697{
Ron Yorston549deab2015-05-18 09:57:51 +02005698 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005699}
5700
5701/*
5702 * Put a string on the stack.
5703 */
5704static void
5705memtodest(const char *p, size_t len, int syntax, int quotes)
5706{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005707 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005708
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005709 if (!len)
5710 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005711
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005712 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5713
5714 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005715 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005716 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005717 int n = SIT(c, syntax);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005718 if ((quotes & QUOTES_ESC)
5719 && ((n == CCTL)
5720 || (((quotes & EXP_FULL) || syntax != BASESYNTAX)
5721 && n == CBACK)
5722 )
5723 ) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005724 USTPUTC(CTLESC, q);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02005725 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005726 } else if (!(quotes & QUOTES_KEEPNUL))
5727 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005728 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005729 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005730
5731 expdest = q;
5732}
5733
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005734static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005735strtodest(const char *p, int syntax, int quotes)
5736{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005737 size_t len = strlen(p);
5738 memtodest(p, len, syntax, quotes);
5739 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005740}
5741
5742/*
5743 * Record the fact that we have to scan this region of the
5744 * string for IFS characters.
5745 */
5746static void
5747recordregion(int start, int end, int nulonly)
5748{
5749 struct ifsregion *ifsp;
5750
5751 if (ifslastp == NULL) {
5752 ifsp = &ifsfirst;
5753 } else {
5754 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005755 ifsp = ckzalloc(sizeof(*ifsp));
5756 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005757 ifslastp->next = ifsp;
5758 INT_ON;
5759 }
5760 ifslastp = ifsp;
5761 ifslastp->begoff = start;
5762 ifslastp->endoff = end;
5763 ifslastp->nulonly = nulonly;
5764}
5765
5766static void
5767removerecordregions(int endoff)
5768{
5769 if (ifslastp == NULL)
5770 return;
5771
5772 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005773 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005774 struct ifsregion *ifsp;
5775 INT_OFF;
5776 ifsp = ifsfirst.next->next;
5777 free(ifsfirst.next);
5778 ifsfirst.next = ifsp;
5779 INT_ON;
5780 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005781 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005782 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005783 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005784 ifslastp = &ifsfirst;
5785 ifsfirst.endoff = endoff;
5786 }
5787 return;
5788 }
5789
5790 ifslastp = &ifsfirst;
5791 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005792 ifslastp = ifslastp->next;
5793 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005794 struct ifsregion *ifsp;
5795 INT_OFF;
5796 ifsp = ifslastp->next->next;
5797 free(ifslastp->next);
5798 ifslastp->next = ifsp;
5799 INT_ON;
5800 }
5801 if (ifslastp->endoff > endoff)
5802 ifslastp->endoff = endoff;
5803}
5804
5805static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005806exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005807{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005808 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005809 char *name;
5810 struct passwd *pw;
5811 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005812 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005813
5814 name = p + 1;
5815
5816 while ((c = *++p) != '\0') {
5817 switch (c) {
5818 case CTLESC:
5819 return startp;
5820 case CTLQUOTEMARK:
5821 return startp;
5822 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005823 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005824 goto done;
5825 break;
5826 case '/':
5827 case CTLENDVAR:
5828 goto done;
5829 }
5830 }
5831 done:
5832 *p = '\0';
5833 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005834 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005835 } else {
5836 pw = getpwnam(name);
5837 if (pw == NULL)
5838 goto lose;
5839 home = pw->pw_dir;
5840 }
5841 if (!home || !*home)
5842 goto lose;
5843 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005844 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005845 return p;
5846 lose:
5847 *p = c;
5848 return startp;
5849}
5850
5851/*
5852 * Execute a command inside back quotes. If it's a builtin command, we
5853 * want to save its output in a block obtained from malloc. Otherwise
5854 * we fork off a subprocess and get the output of the command via a pipe.
5855 * Should be called with interrupts off.
5856 */
5857struct backcmd { /* result of evalbackcmd */
5858 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005859 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005860 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005861 struct job *jp; /* job structure for command */
5862};
5863
5864/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005865static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005866#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02005867static int evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005868
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005869static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005870evalbackcmd(union node *n, struct backcmd *result)
5871{
5872 int saveherefd;
5873
5874 result->fd = -1;
5875 result->buf = NULL;
5876 result->nleft = 0;
5877 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005878 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005879 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005880
5881 saveherefd = herefd;
5882 herefd = -1;
5883
5884 {
5885 int pip[2];
5886 struct job *jp;
5887
5888 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005889 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005890 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005891 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5892 FORCE_INT_ON;
5893 close(pip[0]);
5894 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005895 /*close(1);*/
5896 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005897 close(pip[1]);
5898 }
5899 eflag = 0;
5900 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5901 /* NOTREACHED */
5902 }
5903 close(pip[1]);
5904 result->fd = pip[0];
5905 result->jp = jp;
5906 }
5907 herefd = saveherefd;
5908 out:
5909 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5910 result->fd, result->buf, result->nleft, result->jp));
5911}
5912
5913/*
5914 * Expand stuff in backwards quotes.
5915 */
5916static void
Ron Yorston549deab2015-05-18 09:57:51 +02005917expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005918{
5919 struct backcmd in;
5920 int i;
5921 char buf[128];
5922 char *p;
5923 char *dest;
5924 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02005925 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005926 struct stackmark smark;
5927
5928 INT_OFF;
5929 setstackmark(&smark);
5930 dest = expdest;
5931 startloc = dest - (char *)stackblock();
5932 grabstackstr(dest);
5933 evalbackcmd(cmd, &in);
5934 popstackmark(&smark);
5935
5936 p = in.buf;
5937 i = in.nleft;
5938 if (i == 0)
5939 goto read;
5940 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02005941 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005942 read:
5943 if (in.fd < 0)
5944 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01005945 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005946 TRACE(("expbackq: read returns %d\n", i));
5947 if (i <= 0)
5948 break;
5949 p = buf;
5950 }
5951
Denis Vlasenko60818682007-09-28 22:07:23 +00005952 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005953 if (in.fd >= 0) {
5954 close(in.fd);
5955 back_exitstatus = waitforjob(in.jp);
5956 }
5957 INT_ON;
5958
5959 /* Eat all trailing newlines */
5960 dest = expdest;
5961 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5962 STUNPUTC(dest);
5963 expdest = dest;
5964
Ron Yorston549deab2015-05-18 09:57:51 +02005965 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005967 TRACE(("evalbackq: size:%d:'%.*s'\n",
5968 (int)((dest - (char *)stackblock()) - startloc),
5969 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005970 stackblock() + startloc));
5971}
5972
Mike Frysinger98c52642009-04-02 10:02:37 +00005973#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005974/*
5975 * Expand arithmetic expression. Backup to start of expression,
5976 * evaluate, place result in (backed up) result, adjust string position.
5977 */
5978static void
Ron Yorston549deab2015-05-18 09:57:51 +02005979expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005980{
5981 char *p, *start;
5982 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005983 int len;
5984
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005985 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005986
5987 /*
5988 * This routine is slightly over-complicated for
5989 * efficiency. Next we scan backwards looking for the
5990 * start of arithmetic.
5991 */
5992 start = stackblock();
5993 p = expdest - 1;
5994 *p = '\0';
5995 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005996 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005997 int esc;
5998
Denys Vlasenkocd716832009-11-28 22:14:02 +01005999 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000 p--;
6001#if DEBUG
6002 if (p < start) {
6003 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
6004 }
6005#endif
6006 }
6007
6008 esc = esclen(start, p);
6009 if (!(esc % 2)) {
6010 break;
6011 }
6012
6013 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01006014 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006015
6016 begoff = p - start;
6017
6018 removerecordregions(begoff);
6019
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006020 expdest = p;
6021
Ron Yorston549deab2015-05-18 09:57:51 +02006022 if (flag & QUOTES_ESC)
6023 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006024
Ron Yorston549deab2015-05-18 09:57:51 +02006025 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006026
Ron Yorston549deab2015-05-18 09:57:51 +02006027 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006028 recordregion(begoff, begoff + len, 0);
6029}
6030#endif
6031
6032/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006033static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006034
6035/*
6036 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6037 * characters to allow for further processing. Otherwise treat
6038 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006039 *
6040 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6041 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6042 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006043 */
6044static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006045argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006046{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006047 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006048 '=',
6049 ':',
6050 CTLQUOTEMARK,
6051 CTLENDVAR,
6052 CTLESC,
6053 CTLVAR,
6054 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006055#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006056 CTLENDARI,
6057#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006058 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006059 };
6060 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006061 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006062 int inquotes;
6063 size_t length;
6064 int startloc;
6065
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006066 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006067 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006068 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069 reject++;
6070 }
6071 inquotes = 0;
6072 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006073 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006074 char *q;
6075
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006076 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006077 tilde:
6078 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006079 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006080 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006081 }
6082 start:
6083 startloc = expdest - (char *)stackblock();
6084 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006085 unsigned char c;
6086
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006087 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006088 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006089 if (c) {
6090 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006091 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006092 ) {
6093 /* c == '=' || c == ':' || c == CTLENDARI */
6094 length++;
6095 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006096 }
6097 if (length > 0) {
6098 int newloc;
6099 expdest = stack_nputstr(p, length, expdest);
6100 newloc = expdest - (char *)stackblock();
6101 if (breakall && !inquotes && newloc > startloc) {
6102 recordregion(startloc, newloc, 0);
6103 }
6104 startloc = newloc;
6105 }
6106 p += length + 1;
6107 length = 0;
6108
6109 switch (c) {
6110 case '\0':
6111 goto breakloop;
6112 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006113 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006114 p--;
6115 continue;
6116 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006117 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006118 reject++;
6119 /* fall through */
6120 case ':':
6121 /*
6122 * sort of a hack - expand tildes in variable
6123 * assignments (after the first '=' and after ':'s).
6124 */
6125 if (*--p == '~') {
6126 goto tilde;
6127 }
6128 continue;
6129 }
6130
6131 switch (c) {
6132 case CTLENDVAR: /* ??? */
6133 goto breakloop;
6134 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006135 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006136 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006137 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6138 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006139 goto start;
6140 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006141 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006142 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006143 p--;
6144 length++;
6145 startloc++;
6146 }
6147 break;
6148 case CTLESC:
6149 startloc++;
6150 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006151
6152 /*
6153 * Quoted parameter expansion pattern: remove quote
6154 * unless inside inner quotes or we have a literal
6155 * backslash.
6156 */
6157 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6158 EXP_QPAT && *p != '\\')
6159 break;
6160
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006161 goto addquote;
6162 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006163 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006164 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006165 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006166 goto start;
6167 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006168 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006169 argbackq = argbackq->next;
6170 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006171#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172 case CTLENDARI:
6173 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006174 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006175 goto start;
6176#endif
6177 }
6178 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006179 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006180}
6181
6182static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006183scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6184 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006185{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006186 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006187 char c;
6188
6189 loc = startp;
6190 loc2 = rmesc;
6191 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006192 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006193 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006194
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006195 c = *loc2;
6196 if (zero) {
6197 *loc2 = '\0';
6198 s = rmesc;
6199 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006200 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006201
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006202 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006203 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006204 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006205 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006206 loc++;
6207 loc++;
6208 loc2++;
6209 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006210 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006211}
6212
6213static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006214scanright(char *startp, char *rmesc, char *rmescend,
6215 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006216{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006217#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6218 int try2optimize = match_at_start;
6219#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006220 int esc = 0;
6221 char *loc;
6222 char *loc2;
6223
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006224 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6225 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6226 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6227 * Logic:
6228 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6229 * and on each iteration they go back two/one char until they reach the beginning.
6230 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6231 */
6232 /* TODO: document in what other circumstances we are called. */
6233
6234 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006235 int match;
6236 char c = *loc2;
6237 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006238 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006239 *loc2 = '\0';
6240 s = rmesc;
6241 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006242 match = pmatch(pattern, s);
6243 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006244 *loc2 = c;
6245 if (match)
6246 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006247#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6248 if (try2optimize) {
6249 /* Maybe we can optimize this:
6250 * if pattern ends with unescaped *, we can avoid checking
6251 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6252 * it wont match truncated "raw_value_of_" strings too.
6253 */
6254 unsigned plen = strlen(pattern);
6255 /* Does it end with "*"? */
6256 if (plen != 0 && pattern[--plen] == '*') {
6257 /* "xxxx*" is not escaped */
6258 /* "xxx\*" is escaped */
6259 /* "xx\\*" is not escaped */
6260 /* "x\\\*" is escaped */
6261 int slashes = 0;
6262 while (plen != 0 && pattern[--plen] == '\\')
6263 slashes++;
6264 if (!(slashes & 1))
6265 break; /* ends with unescaped "*" */
6266 }
6267 try2optimize = 0;
6268 }
6269#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270 loc--;
6271 if (quotes) {
6272 if (--esc < 0) {
6273 esc = esclen(startp, loc);
6274 }
6275 if (esc % 2) {
6276 esc--;
6277 loc--;
6278 }
6279 }
6280 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006281 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006282}
6283
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006284static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006285static void
6286varunset(const char *end, const char *var, const char *umsg, int varflags)
6287{
6288 const char *msg;
6289 const char *tail;
6290
6291 tail = nullstr;
6292 msg = "parameter not set";
6293 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006294 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006295 if (varflags & VSNUL)
6296 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006297 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006298 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006299 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006300 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006301 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006302}
6303
6304static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006305subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006306 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006307{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006308 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006309 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006310 char *startp;
6311 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006312 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006313 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006314 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006315 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006316 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006317 int amount, resetloc;
6318 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006319 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006320 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006321
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006322 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6323 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006324
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006325 herefd = -1;
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006326 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006327 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6328 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006329 STPUTC('\0', expdest);
6330 herefd = saveherefd;
6331 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006332 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006333
6334 switch (subtype) {
6335 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006336 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006337 amount = startp - expdest;
6338 STADJUST(amount, expdest);
6339 return startp;
6340
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006341 case VSQUESTION:
6342 varunset(p, varname, startp, varflags);
6343 /* NOTREACHED */
6344
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006345#if ENABLE_ASH_BASH_COMPAT
6346 case VSSUBSTR:
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +02006347//TODO: support more general format ${v:EXPR:EXPR},
6348// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006349 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006350 /* Read POS in ${var:POS:LEN} */
6351 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006352 len = str - startp - 1;
6353
6354 /* *loc != '\0', guaranteed by parser */
6355 if (quotes) {
6356 char *ptr;
6357
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006358 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006359 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006360 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006361 len--;
6362 ptr++;
6363 }
6364 }
6365 }
6366 orig_len = len;
6367
6368 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006369 /* ${var::LEN} */
6370 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006371 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006372 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006373 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006374 while (*loc && *loc != ':') {
6375 /* TODO?
6376 * bash complains on: var=qwe; echo ${var:1a:123}
6377 if (!isdigit(*loc))
6378 ash_msg_and_raise_error(msg_illnum, str);
6379 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006380 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006381 }
6382 if (*loc++ == ':') {
6383 len = number(loc);
6384 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006385 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006386 if (pos < 0) {
6387 /* ${VAR:$((-n)):l} starts n chars from the end */
6388 pos = orig_len + pos;
6389 }
6390 if ((unsigned)pos >= orig_len) {
6391 /* apart from obvious ${VAR:999999:l},
6392 * covers ${VAR:$((-9999999)):l} - result is ""
6393 * (bash-compat)
6394 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006395 pos = 0;
6396 len = 0;
6397 }
6398 if (len > (orig_len - pos))
6399 len = orig_len - pos;
6400
6401 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006402 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006403 str++;
6404 }
6405 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006406 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006407 *loc++ = *str++;
6408 *loc++ = *str++;
6409 }
6410 *loc = '\0';
6411 amount = loc - expdest;
6412 STADJUST(amount, expdest);
6413 return loc;
6414#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006415 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006416
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006417 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006418
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006419 /* We'll comeback here if we grow the stack while handling
6420 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6421 * stack will need rebasing, and we'll need to remove our work
6422 * areas each time
6423 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006424 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006425
6426 amount = expdest - ((char *)stackblock() + resetloc);
6427 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006428 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006429
6430 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006431 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006432 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006433 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006434 if (rmesc != startp) {
6435 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006436 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006437 }
6438 }
6439 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006440 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006441 /*
6442 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6443 * The result is a_\_z_c (not a\_\_z_c)!
6444 *
6445 * The search pattern and replace string treat backslashes differently!
6446 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6447 * and string. It's only used on the first call.
6448 */
6449 preglob(str, IF_ASH_BASH_COMPAT(
6450 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6451 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006452
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006453#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006454 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006455 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006456 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006457
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006458 if (!repl) {
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02006459 repl = strchr(str, CTLESC);
6460 if (repl)
Ron Yorston417622c2015-05-18 09:59:14 +02006461 *repl++ = '\0';
6462 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006463 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006464 }
Ron Yorston417622c2015-05-18 09:59:14 +02006465 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006466
6467 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006468 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006469 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006470
6471 len = 0;
6472 idx = startp;
6473 end = str - 1;
6474 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006475 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006476 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006477 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006478 if (!loc) {
6479 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006480 char *restart_detect = stackblock();
6481 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006482 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006483 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006484 idx++;
6485 len++;
6486 STPUTC(*idx, expdest);
6487 }
6488 if (stackblock() != restart_detect)
6489 goto restart;
6490 idx++;
6491 len++;
6492 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006493 /* continue; - prone to quadratic behavior, smarter code: */
6494 if (idx >= end)
6495 break;
6496 if (str[0] == '*') {
6497 /* Pattern is "*foo". If "*foo" does not match "long_string",
6498 * it would never match "ong_string" etc, no point in trying.
6499 */
6500 goto skip_matching;
6501 }
6502 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006503 }
6504
6505 if (subtype == VSREPLACEALL) {
6506 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006507 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006508 idx++;
6509 idx++;
6510 rmesc++;
6511 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006512 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006513 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006514 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006515
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006516 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006517 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006518 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006519 if (quotes && *loc == '\\') {
6520 STPUTC(CTLESC, expdest);
6521 len++;
6522 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006523 STPUTC(*loc, expdest);
6524 if (stackblock() != restart_detect)
6525 goto restart;
6526 len++;
6527 }
6528
6529 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006530 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006531 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006532 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006533 STPUTC(*idx, expdest);
6534 if (stackblock() != restart_detect)
6535 goto restart;
6536 len++;
6537 idx++;
6538 }
6539 break;
6540 }
6541 }
6542
6543 /* We've put the replaced text into a buffer at workloc, now
6544 * move it to the right place and adjust the stack.
6545 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006546 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006547 startp = (char *)stackblock() + startloc;
6548 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006549 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006550 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006551 STADJUST(-amount, expdest);
6552 return startp;
6553 }
6554#endif /* ENABLE_ASH_BASH_COMPAT */
6555
6556 subtype -= VSTRIMRIGHT;
6557#if DEBUG
6558 if (subtype < 0 || subtype > 7)
6559 abort();
6560#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006561 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006562 zero = subtype >> 1;
6563 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6564 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6565
6566 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6567 if (loc) {
6568 if (zero) {
6569 memmove(startp, loc, str - loc);
6570 loc = startp + (str - loc) - 1;
6571 }
6572 *loc = '\0';
6573 amount = loc - expdest;
6574 STADJUST(amount, expdest);
6575 }
6576 return loc;
6577}
6578
6579/*
6580 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006581 * name parameter (examples):
6582 * ash -c 'echo $1' name:'1='
6583 * ash -c 'echo $qwe' name:'qwe='
6584 * ash -c 'echo $$' name:'$='
6585 * ash -c 'echo ${$}' name:'$='
6586 * ash -c 'echo ${$##q}' name:'$=q'
6587 * ash -c 'echo ${#$}' name:'$='
6588 * note: examples with bad shell syntax:
6589 * ash -c 'echo ${#$1}' name:'$=1'
6590 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006591 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006592static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006593varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006594{
Mike Frysinger98c52642009-04-02 10:02:37 +00006595 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006596 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006597 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006598 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006599 int sep;
Ron Yorston549deab2015-05-18 09:57:51 +02006600 int quoted = flags & EXP_QUOTED;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006601 int subtype = varflags & VSTYPE;
6602 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6603 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006604 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006605
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006606 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
6607
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006608 switch (*name) {
6609 case '$':
6610 num = rootpid;
6611 goto numvar;
6612 case '?':
6613 num = exitstatus;
6614 goto numvar;
6615 case '#':
6616 num = shellparam.nparam;
6617 goto numvar;
6618 case '!':
6619 num = backgndpid;
6620 if (num == 0)
6621 return -1;
6622 numvar:
6623 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006624 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006625 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006626 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006627 for (i = NOPTS - 1; i >= 0; i--) {
6628 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006629 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006630 len++;
6631 }
6632 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006633 check_1char_name:
6634#if 0
6635 /* handles cases similar to ${#$1} */
6636 if (name[2] != '\0')
6637 raise_error_syntax("bad substitution");
6638#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006639 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006640 case '@': {
6641 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006642 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006643
6644 if (quoted && (flags & EXP_FULL)) {
6645 /* note: this is not meant as PEOF value */
6646 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006647 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006648 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006649 /* fall through */
6650 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006651 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006652 param:
6653 ap = shellparam.p;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006654 sepc = sep;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006655 if (!ap)
6656 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006657 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006658 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006659
6660 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006661 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006662 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006663 }
6664 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006665 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006666 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006667 case '0':
6668 case '1':
6669 case '2':
6670 case '3':
6671 case '4':
6672 case '5':
6673 case '6':
6674 case '7':
6675 case '8':
6676 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006677 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006678 if (num < 0 || num > shellparam.nparam)
6679 return -1;
6680 p = num ? shellparam.p[num - 1] : arg0;
6681 goto value;
6682 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006683 /* NB: name has form "VAR=..." */
6684
6685 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6686 * which should be considered before we check variables. */
6687 if (var_str_list) {
6688 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6689 p = NULL;
6690 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006691 char *str, *eq;
6692 str = var_str_list->text;
6693 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006694 if (!eq) /* stop at first non-assignment */
6695 break;
6696 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006697 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006698 && strncmp(str, name, name_len) == 0
6699 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006700 p = eq;
6701 /* goto value; - WRONG! */
6702 /* think "A=1 A=2 B=$A" */
6703 }
6704 var_str_list = var_str_list->next;
6705 } while (var_str_list);
6706 if (p)
6707 goto value;
6708 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006709 p = lookupvar(name);
6710 value:
6711 if (!p)
6712 return -1;
6713
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006714 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006715#if ENABLE_UNICODE_SUPPORT
6716 if (subtype == VSLENGTH && len > 0) {
6717 reinit_unicode_for_ash();
6718 if (unicode_status == UNICODE_ON) {
Ron Yorston3e3bfb82016-03-18 11:29:19 +00006719 STADJUST(-len, expdest);
6720 discard = 0;
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006721 len = unicode_strlen(p);
6722 }
6723 }
6724#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006725 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006726 }
6727
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006728 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006729 STADJUST(-len, expdest);
6730 return len;
6731}
6732
6733/*
6734 * Expand a variable, and return a pointer to the next character in the
6735 * input string.
6736 */
6737static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006738evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006739{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006740 char varflags;
6741 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006742 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006743 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006744 char *var;
6745 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006746 int startloc;
6747 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006748
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006749 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006750 subtype = varflags & VSTYPE;
Ron Yorston549deab2015-05-18 09:57:51 +02006751 quoted = flags & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006752 var = p;
6753 easy = (!quoted || (*var == '@' && shellparam.nparam));
6754 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006755 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006756
6757 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006758 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006759 if (varflags & VSNUL)
6760 varlen--;
6761
6762 if (subtype == VSPLUS) {
6763 varlen = -1 - varlen;
6764 goto vsplus;
6765 }
6766
6767 if (subtype == VSMINUS) {
6768 vsplus:
6769 if (varlen < 0) {
6770 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006771 p,
Ron Yorston549deab2015-05-18 09:57:51 +02006772 flags | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006773 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006774 );
6775 goto end;
6776 }
6777 if (easy)
6778 goto record;
6779 goto end;
6780 }
6781
6782 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6783 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006784 if (subevalvar(p, var, /* strloc: */ 0,
6785 subtype, startloc, varflags,
Ron Yorston549deab2015-05-18 09:57:51 +02006786 /* quotes: */ flags & ~QUOTES_ESC,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006787 var_str_list)
6788 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006789 varflags &= ~VSNUL;
6790 /*
6791 * Remove any recorded regions beyond
6792 * start of variable
6793 */
6794 removerecordregions(startloc);
6795 goto again;
6796 }
6797 goto end;
6798 }
6799 if (easy)
6800 goto record;
6801 goto end;
6802 }
6803
6804 if (varlen < 0 && uflag)
6805 varunset(p, var, 0, 0);
6806
6807 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006808 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006809 goto record;
6810 }
6811
6812 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006813 if (easy)
6814 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006815 goto end;
6816 }
6817
6818#if DEBUG
6819 switch (subtype) {
6820 case VSTRIMLEFT:
6821 case VSTRIMLEFTMAX:
6822 case VSTRIMRIGHT:
6823 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006824#if ENABLE_ASH_BASH_COMPAT
6825 case VSSUBSTR:
6826 case VSREPLACE:
6827 case VSREPLACEALL:
6828#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006829 break;
6830 default:
6831 abort();
6832 }
6833#endif
6834
6835 if (varlen >= 0) {
6836 /*
6837 * Terminate the string and start recording the pattern
6838 * right after it
6839 */
6840 STPUTC('\0', expdest);
6841 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006842 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006843 startloc, varflags, flags, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006844 int amount = expdest - (
6845 (char *)stackblock() + patloc - 1
6846 );
6847 STADJUST(-amount, expdest);
6848 }
6849 /* Remove any recorded regions beyond start of variable */
6850 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006851 record:
6852 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006853 }
6854
6855 end:
6856 if (subtype != VSNORMAL) { /* skip to end of alternative */
6857 int nesting = 1;
6858 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006859 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006860 if (c == CTLESC)
6861 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006862 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006863 if (varlen >= 0)
6864 argbackq = argbackq->next;
6865 } else if (c == CTLVAR) {
6866 if ((*p++ & VSTYPE) != VSNORMAL)
6867 nesting++;
6868 } else if (c == CTLENDVAR) {
6869 if (--nesting == 0)
6870 break;
6871 }
6872 }
6873 }
6874 return p;
6875}
6876
6877/*
6878 * Break the argument string into pieces based upon IFS and add the
6879 * strings to the argument list. The regions of the string to be
6880 * searched for IFS characters have been stored by recordregion.
6881 */
6882static void
6883ifsbreakup(char *string, struct arglist *arglist)
6884{
6885 struct ifsregion *ifsp;
6886 struct strlist *sp;
6887 char *start;
6888 char *p;
6889 char *q;
6890 const char *ifs, *realifs;
6891 int ifsspc;
6892 int nulonly;
6893
6894 start = string;
6895 if (ifslastp != NULL) {
6896 ifsspc = 0;
6897 nulonly = 0;
6898 realifs = ifsset() ? ifsval() : defifs;
6899 ifsp = &ifsfirst;
6900 do {
6901 p = string + ifsp->begoff;
6902 nulonly = ifsp->nulonly;
6903 ifs = nulonly ? nullstr : realifs;
6904 ifsspc = 0;
6905 while (p < string + ifsp->endoff) {
6906 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006907 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006908 p++;
6909 if (!strchr(ifs, *p)) {
6910 p++;
6911 continue;
6912 }
6913 if (!nulonly)
6914 ifsspc = (strchr(defifs, *p) != NULL);
6915 /* Ignore IFS whitespace at start */
6916 if (q == start && ifsspc) {
6917 p++;
6918 start = p;
6919 continue;
6920 }
6921 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006922 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006923 sp->text = start;
6924 *arglist->lastp = sp;
6925 arglist->lastp = &sp->next;
6926 p++;
6927 if (!nulonly) {
6928 for (;;) {
6929 if (p >= string + ifsp->endoff) {
6930 break;
6931 }
6932 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006933 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006934 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006935 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006936 p = q;
6937 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006938 }
6939 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006940 if (ifsspc) {
6941 p++;
6942 ifsspc = 0;
6943 } else {
6944 p = q;
6945 break;
6946 }
6947 } else
6948 p++;
6949 }
6950 }
6951 start = p;
6952 } /* while */
6953 ifsp = ifsp->next;
6954 } while (ifsp != NULL);
6955 if (nulonly)
6956 goto add;
6957 }
6958
6959 if (!*start)
6960 return;
6961
6962 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006963 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006964 sp->text = start;
6965 *arglist->lastp = sp;
6966 arglist->lastp = &sp->next;
6967}
6968
6969static void
6970ifsfree(void)
6971{
6972 struct ifsregion *p;
6973
6974 INT_OFF;
6975 p = ifsfirst.next;
6976 do {
6977 struct ifsregion *ifsp;
6978 ifsp = p->next;
6979 free(p);
6980 p = ifsp;
6981 } while (p);
6982 ifslastp = NULL;
6983 ifsfirst.next = NULL;
6984 INT_ON;
6985}
6986
6987/*
6988 * Add a file name to the list.
6989 */
6990static void
6991addfname(const char *name)
6992{
6993 struct strlist *sp;
6994
Denis Vlasenko597906c2008-02-20 16:38:54 +00006995 sp = stzalloc(sizeof(*sp));
Denys Vlasenko8e2bc472016-09-28 23:02:57 +02006996 sp->text = sstrdup(name);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006997 *exparg.lastp = sp;
6998 exparg.lastp = &sp->next;
6999}
7000
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007001/* If we want to use glob() from libc... */
7002#if 1
7003
7004/* Add the result of glob() to the list */
7005static void
7006addglob(const glob_t *pglob)
7007{
7008 char **p = pglob->gl_pathv;
7009
7010 do {
7011 addfname(*p);
7012 } while (*++p);
7013}
7014static void
7015expandmeta(struct strlist *str /*, int flag*/)
7016{
7017 /* TODO - EXP_REDIR */
7018
7019 while (str) {
7020 char *p;
7021 glob_t pglob;
7022 int i;
7023
7024 if (fflag)
7025 goto nometa;
7026 INT_OFF;
7027 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7028 /*
7029 * GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7030 * TODO?: GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7031 */
7032 i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7033 if (p != str->text)
7034 free(p);
7035 switch (i) {
7036 case 0:
7037 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7038 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7039 goto nometa2;
7040 addglob(&pglob);
7041 globfree(&pglob);
7042 INT_ON;
7043 break;
7044 case GLOB_NOMATCH:
7045nometa2:
7046 globfree(&pglob);
7047 INT_ON;
7048nometa:
7049 *exparg.lastp = str;
7050 rmescapes(str->text, 0);
7051 exparg.lastp = &str->next;
7052 break;
7053 default: /* GLOB_NOSPACE */
7054 globfree(&pglob);
7055 INT_ON;
7056 ash_msg_and_raise_error(bb_msg_memory_exhausted);
7057 }
7058 str = str->next;
7059 }
7060}
7061
7062#else
7063/* Homegrown globbing code. (dash also has both, uses homegrown one.) */
7064
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007065/*
7066 * Do metacharacter (i.e. *, ?, [...]) expansion.
7067 */
7068static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007069expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007070{
7071 char *p;
7072 const char *cp;
7073 char *start;
7074 char *endname;
7075 int metaflag;
7076 struct stat statb;
7077 DIR *dirp;
7078 struct dirent *dp;
7079 int atend;
7080 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01007081 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007082
7083 metaflag = 0;
7084 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01007085 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007086 if (*p == '*' || *p == '?')
7087 metaflag = 1;
7088 else if (*p == '[') {
7089 char *q = p + 1;
7090 if (*q == '!')
7091 q++;
7092 for (;;) {
7093 if (*q == '\\')
7094 q++;
7095 if (*q == '/' || *q == '\0')
7096 break;
7097 if (*++q == ']') {
7098 metaflag = 1;
7099 break;
7100 }
7101 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007102 } else {
7103 if (*p == '\\')
7104 esc++;
7105 if (p[esc] == '/') {
7106 if (metaflag)
7107 break;
7108 start = p + esc + 1;
7109 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007110 }
7111 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007112 if (metaflag == 0) { /* we've reached the end of the file name */
7113 if (enddir != expdir)
7114 metaflag++;
7115 p = name;
7116 do {
7117 if (*p == '\\')
7118 p++;
7119 *enddir++ = *p;
7120 } while (*p++);
7121 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7122 addfname(expdir);
7123 return;
7124 }
7125 endname = p;
7126 if (name < start) {
7127 p = name;
7128 do {
7129 if (*p == '\\')
7130 p++;
7131 *enddir++ = *p++;
7132 } while (p < start);
7133 }
7134 if (enddir == expdir) {
7135 cp = ".";
7136 } else if (enddir == expdir + 1 && *expdir == '/') {
7137 cp = "/";
7138 } else {
7139 cp = expdir;
7140 enddir[-1] = '\0';
7141 }
7142 dirp = opendir(cp);
7143 if (dirp == NULL)
7144 return;
7145 if (enddir != expdir)
7146 enddir[-1] = '/';
7147 if (*endname == 0) {
7148 atend = 1;
7149 } else {
7150 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007151 *endname = '\0';
7152 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007153 }
7154 matchdot = 0;
7155 p = start;
7156 if (*p == '\\')
7157 p++;
7158 if (*p == '.')
7159 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007160 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007161 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007162 continue;
7163 if (pmatch(start, dp->d_name)) {
7164 if (atend) {
7165 strcpy(enddir, dp->d_name);
7166 addfname(expdir);
7167 } else {
7168 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7169 continue;
7170 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007171 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007172 }
7173 }
7174 }
7175 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007176 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007177 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007178}
7179
7180static struct strlist *
7181msort(struct strlist *list, int len)
7182{
7183 struct strlist *p, *q = NULL;
7184 struct strlist **lpp;
7185 int half;
7186 int n;
7187
7188 if (len <= 1)
7189 return list;
7190 half = len >> 1;
7191 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007192 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007193 q = p;
7194 p = p->next;
7195 }
7196 q->next = NULL; /* terminate first half of list */
7197 q = msort(list, half); /* sort first half of list */
7198 p = msort(p, len - half); /* sort second half */
7199 lpp = &list;
7200 for (;;) {
7201#if ENABLE_LOCALE_SUPPORT
7202 if (strcoll(p->text, q->text) < 0)
7203#else
7204 if (strcmp(p->text, q->text) < 0)
7205#endif
7206 {
7207 *lpp = p;
7208 lpp = &p->next;
7209 p = *lpp;
7210 if (p == NULL) {
7211 *lpp = q;
7212 break;
7213 }
7214 } else {
7215 *lpp = q;
7216 lpp = &q->next;
7217 q = *lpp;
7218 if (q == NULL) {
7219 *lpp = p;
7220 break;
7221 }
7222 }
7223 }
7224 return list;
7225}
7226
7227/*
7228 * Sort the results of file name expansion. It calculates the number of
7229 * strings to sort and then calls msort (short for merge sort) to do the
7230 * work.
7231 */
7232static struct strlist *
7233expsort(struct strlist *str)
7234{
7235 int len;
7236 struct strlist *sp;
7237
7238 len = 0;
7239 for (sp = str; sp; sp = sp->next)
7240 len++;
7241 return msort(str, len);
7242}
7243
7244static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007245expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007246{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007247 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007248 '*', '?', '[', 0
7249 };
7250 /* TODO - EXP_REDIR */
7251
7252 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007253 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007254 struct strlist **savelastp;
7255 struct strlist *sp;
7256 char *p;
7257
7258 if (fflag)
7259 goto nometa;
7260 if (!strpbrk(str->text, metachars))
7261 goto nometa;
7262 savelastp = exparg.lastp;
7263
7264 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007265 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007266 {
7267 int i = strlen(str->text);
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007268//BUGGY estimation of how long expanded name can be
7269 expdir = ckmalloc(i < 2048 ? 2048 : i+1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007270 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007271 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007272 free(expdir);
7273 if (p != str->text)
7274 free(p);
7275 INT_ON;
7276 if (exparg.lastp == savelastp) {
7277 /*
7278 * no matches
7279 */
7280 nometa:
7281 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007282 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007283 exparg.lastp = &str->next;
7284 } else {
7285 *exparg.lastp = NULL;
7286 *savelastp = sp = expsort(*savelastp);
7287 while (sp->next != NULL)
7288 sp = sp->next;
7289 exparg.lastp = &sp->next;
7290 }
7291 str = str->next;
7292 }
7293}
Denys Vlasenkob3f29b42016-09-21 16:25:58 +02007294#endif /* our globbing code */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007295
7296/*
7297 * Perform variable substitution and command substitution on an argument,
7298 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7299 * perform splitting and file name expansion. When arglist is NULL, perform
7300 * here document expansion.
7301 */
7302static void
7303expandarg(union node *arg, struct arglist *arglist, int flag)
7304{
7305 struct strlist *sp;
7306 char *p;
7307
7308 argbackq = arg->narg.backquote;
7309 STARTSTACKSTR(expdest);
7310 ifsfirst.next = NULL;
7311 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007312 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007313 argstr(arg->narg.text, flag,
7314 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007315 p = _STPUTC('\0', expdest);
7316 expdest = p - 1;
7317 if (arglist == NULL) {
7318 return; /* here document expanded */
7319 }
7320 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007321 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007322 exparg.lastp = &exparg.list;
7323 /*
7324 * TODO - EXP_REDIR
7325 */
7326 if (flag & EXP_FULL) {
7327 ifsbreakup(p, &exparg);
7328 *exparg.lastp = NULL;
7329 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007330 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007331 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007332 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007333 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007334 TRACE(("expandarg: rmescapes:'%s'\n", p));
7335 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007336 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007337 sp->text = p;
7338 *exparg.lastp = sp;
7339 exparg.lastp = &sp->next;
7340 }
7341 if (ifsfirst.next)
7342 ifsfree();
7343 *exparg.lastp = NULL;
7344 if (exparg.list) {
7345 *arglist->lastp = exparg.list;
7346 arglist->lastp = exparg.lastp;
7347 }
7348}
7349
7350/*
7351 * Expand shell variables and backquotes inside a here document.
7352 */
7353static void
7354expandhere(union node *arg, int fd)
7355{
7356 herefd = fd;
Ron Yorston549deab2015-05-18 09:57:51 +02007357 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007358 full_write(fd, stackblock(), expdest - (char *)stackblock());
7359}
7360
7361/*
7362 * Returns true if the pattern matches the string.
7363 */
7364static int
7365patmatch(char *pattern, const char *string)
7366{
Ron Yorston549deab2015-05-18 09:57:51 +02007367 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007368}
7369
7370/*
7371 * See if a pattern matches in a case statement.
7372 */
7373static int
7374casematch(union node *pattern, char *val)
7375{
7376 struct stackmark smark;
7377 int result;
7378
7379 setstackmark(&smark);
7380 argbackq = pattern->narg.backquote;
7381 STARTSTACKSTR(expdest);
7382 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007383 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7384 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007385 STACKSTRNUL(expdest);
7386 result = patmatch(stackblock(), val);
7387 popstackmark(&smark);
7388 return result;
7389}
7390
7391
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007392/* ============ find_command */
7393
7394struct builtincmd {
7395 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007396 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007397 /* unsigned flags; */
7398};
7399#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007400/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007401 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007402#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007403#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007404
7405struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007406 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007407 union param {
7408 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007409 /* index >= 0 for commands without path (slashes) */
7410 /* (TODO: what exactly does the value mean? PATH position?) */
7411 /* index == -1 for commands with slashes */
7412 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007413 const struct builtincmd *cmd;
7414 struct funcnode *func;
7415 } u;
7416};
7417/* values of cmdtype */
7418#define CMDUNKNOWN -1 /* no entry in table for command */
7419#define CMDNORMAL 0 /* command is an executable program */
7420#define CMDFUNCTION 1 /* command is a shell function */
7421#define CMDBUILTIN 2 /* command is a shell builtin */
7422
7423/* action to find_command() */
7424#define DO_ERR 0x01 /* prints errors */
7425#define DO_ABS 0x02 /* checks absolute paths */
7426#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7427#define DO_ALTPATH 0x08 /* using alternate path */
7428#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7429
7430static void find_command(char *, struct cmdentry *, int, const char *);
7431
7432
7433/* ============ Hashing commands */
7434
7435/*
7436 * When commands are first encountered, they are entered in a hash table.
7437 * This ensures that a full path search will not have to be done for them
7438 * on each invocation.
7439 *
7440 * We should investigate converting to a linear search, even though that
7441 * would make the command name "hash" a misnomer.
7442 */
7443
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007444struct tblentry {
7445 struct tblentry *next; /* next entry in hash chain */
7446 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007447 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007448 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007449 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007450};
7451
Denis Vlasenko01631112007-12-16 17:20:38 +00007452static struct tblentry **cmdtable;
7453#define INIT_G_cmdtable() do { \
7454 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7455} while (0)
7456
7457static int builtinloc = -1; /* index in path of %builtin, or -1 */
7458
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007459
7460static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007461tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007462{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007463#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007464 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007465 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007466 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007467 while (*envp)
7468 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007469 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007470 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007471 /* re-exec ourselves with the new arguments */
7472 execve(bb_busybox_exec_path, argv, envp);
7473 /* If they called chroot or otherwise made the binary no longer
7474 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007475 }
7476#endif
7477
7478 repeat:
7479#ifdef SYSV
7480 do {
7481 execve(cmd, argv, envp);
7482 } while (errno == EINTR);
7483#else
7484 execve(cmd, argv, envp);
7485#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007486 if (cmd == (char*) bb_busybox_exec_path) {
7487 /* We already visited ENOEXEC branch below, don't do it again */
7488//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007489 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007490 return;
7491 }
7492 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007493 /* Run "cmd" as a shell script:
7494 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7495 * "If the execve() function fails with ENOEXEC, the shell
7496 * shall execute a command equivalent to having a shell invoked
7497 * with the command name as its first operand,
7498 * with any remaining arguments passed to the new shell"
7499 *
7500 * That is, do not use $SHELL, user's shell, or /bin/sh;
7501 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007502 *
7503 * Note that bash reads ~80 chars of the file, and if it sees
7504 * a zero byte before it sees newline, it doesn't try to
7505 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007506 * message and exit code 126. For one, this prevents attempts
7507 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007508 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007509 char **ap;
7510 char **new;
7511
7512 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007513 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007514 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7515 new[0] = (char*) "ash";
7516 new[1] = cmd;
7517 ap = new + 2;
7518 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007519 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007520 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007521 argv = new;
7522 goto repeat;
7523 }
7524}
7525
7526/*
7527 * Exec a program. Never returns. If you change this routine, you may
7528 * have to change the find_command routine as well.
7529 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007530static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007531static void
7532shellexec(char **argv, const char *path, int idx)
7533{
7534 char *cmdname;
7535 int e;
7536 char **envp;
7537 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007538 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007539
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007540 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007541 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007542 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007543#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007544 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007545#endif
7546 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007547 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007548 if (applet_no >= 0) {
7549 /* We tried execing ourself, but it didn't work.
7550 * Maybe /proc/self/exe doesn't exist?
7551 * Try $PATH search.
7552 */
7553 goto try_PATH;
7554 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007555 e = errno;
7556 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007557 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007558 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007559 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007560 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007561 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007562 if (errno != ENOENT && errno != ENOTDIR)
7563 e = errno;
7564 }
7565 stunalloc(cmdname);
7566 }
7567 }
7568
7569 /* Map to POSIX errors */
7570 switch (e) {
7571 case EACCES:
7572 exerrno = 126;
7573 break;
7574 case ENOENT:
7575 exerrno = 127;
7576 break;
7577 default:
7578 exerrno = 2;
7579 break;
7580 }
7581 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007582 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7583 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007584 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7585 /* NOTREACHED */
7586}
7587
7588static void
7589printentry(struct tblentry *cmdp)
7590{
7591 int idx;
7592 const char *path;
7593 char *name;
7594
7595 idx = cmdp->param.index;
7596 path = pathval();
7597 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007598 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007599 stunalloc(name);
7600 } while (--idx >= 0);
7601 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7602}
7603
7604/*
7605 * Clear out command entries. The argument specifies the first entry in
7606 * PATH which has changed.
7607 */
7608static void
7609clearcmdentry(int firstchange)
7610{
7611 struct tblentry **tblp;
7612 struct tblentry **pp;
7613 struct tblentry *cmdp;
7614
7615 INT_OFF;
7616 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7617 pp = tblp;
7618 while ((cmdp = *pp) != NULL) {
7619 if ((cmdp->cmdtype == CMDNORMAL &&
7620 cmdp->param.index >= firstchange)
7621 || (cmdp->cmdtype == CMDBUILTIN &&
7622 builtinloc >= firstchange)
7623 ) {
7624 *pp = cmdp->next;
7625 free(cmdp);
7626 } else {
7627 pp = &cmdp->next;
7628 }
7629 }
7630 }
7631 INT_ON;
7632}
7633
7634/*
7635 * Locate a command in the command hash table. If "add" is nonzero,
7636 * add the command to the table if it is not already present. The
7637 * variable "lastcmdentry" is set to point to the address of the link
7638 * pointing to the entry, so that delete_cmd_entry can delete the
7639 * entry.
7640 *
7641 * Interrupts must be off if called with add != 0.
7642 */
7643static struct tblentry **lastcmdentry;
7644
7645static struct tblentry *
7646cmdlookup(const char *name, int add)
7647{
7648 unsigned int hashval;
7649 const char *p;
7650 struct tblentry *cmdp;
7651 struct tblentry **pp;
7652
7653 p = name;
7654 hashval = (unsigned char)*p << 4;
7655 while (*p)
7656 hashval += (unsigned char)*p++;
7657 hashval &= 0x7FFF;
7658 pp = &cmdtable[hashval % CMDTABLESIZE];
7659 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7660 if (strcmp(cmdp->cmdname, name) == 0)
7661 break;
7662 pp = &cmdp->next;
7663 }
7664 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007665 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7666 + strlen(name)
7667 /* + 1 - already done because
7668 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007669 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007670 cmdp->cmdtype = CMDUNKNOWN;
7671 strcpy(cmdp->cmdname, name);
7672 }
7673 lastcmdentry = pp;
7674 return cmdp;
7675}
7676
7677/*
7678 * Delete the command entry returned on the last lookup.
7679 */
7680static void
7681delete_cmd_entry(void)
7682{
7683 struct tblentry *cmdp;
7684
7685 INT_OFF;
7686 cmdp = *lastcmdentry;
7687 *lastcmdentry = cmdp->next;
7688 if (cmdp->cmdtype == CMDFUNCTION)
7689 freefunc(cmdp->param.func);
7690 free(cmdp);
7691 INT_ON;
7692}
7693
7694/*
7695 * Add a new command entry, replacing any existing command entry for
7696 * the same name - except special builtins.
7697 */
7698static void
7699addcmdentry(char *name, struct cmdentry *entry)
7700{
7701 struct tblentry *cmdp;
7702
7703 cmdp = cmdlookup(name, 1);
7704 if (cmdp->cmdtype == CMDFUNCTION) {
7705 freefunc(cmdp->param.func);
7706 }
7707 cmdp->cmdtype = entry->cmdtype;
7708 cmdp->param = entry->u;
7709 cmdp->rehash = 0;
7710}
7711
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007712static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007713hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007714{
7715 struct tblentry **pp;
7716 struct tblentry *cmdp;
7717 int c;
7718 struct cmdentry entry;
7719 char *name;
7720
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007721 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007722 clearcmdentry(0);
7723 return 0;
7724 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007725
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007726 if (*argptr == NULL) {
7727 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7728 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7729 if (cmdp->cmdtype == CMDNORMAL)
7730 printentry(cmdp);
7731 }
7732 }
7733 return 0;
7734 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007735
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007736 c = 0;
7737 while ((name = *argptr) != NULL) {
7738 cmdp = cmdlookup(name, 0);
7739 if (cmdp != NULL
7740 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007741 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7742 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007743 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007744 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007745 find_command(name, &entry, DO_ERR, pathval());
7746 if (entry.cmdtype == CMDUNKNOWN)
7747 c = 1;
7748 argptr++;
7749 }
7750 return c;
7751}
7752
7753/*
7754 * Called when a cd is done. Marks all commands so the next time they
7755 * are executed they will be rehashed.
7756 */
7757static void
7758hashcd(void)
7759{
7760 struct tblentry **pp;
7761 struct tblentry *cmdp;
7762
7763 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7764 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007765 if (cmdp->cmdtype == CMDNORMAL
7766 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007767 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007768 && builtinloc > 0)
7769 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007770 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007771 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007772 }
7773 }
7774}
7775
7776/*
7777 * Fix command hash table when PATH changed.
7778 * Called before PATH is changed. The argument is the new value of PATH;
7779 * pathval() still returns the old value at this point.
7780 * Called with interrupts off.
7781 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007782static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007783changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007784{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007785 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007786 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007787 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007788 int idx_bltin;
7789
7790 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007791 firstchange = 9999; /* assume no change */
7792 idx = 0;
7793 idx_bltin = -1;
7794 for (;;) {
7795 if (*old != *new) {
7796 firstchange = idx;
7797 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007798 || (*old == ':' && *new == '\0')
7799 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007800 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007801 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007802 old = new; /* ignore subsequent differences */
7803 }
7804 if (*new == '\0')
7805 break;
7806 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7807 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007808 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007809 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007810 new++;
7811 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007812 }
7813 if (builtinloc < 0 && idx_bltin >= 0)
7814 builtinloc = idx_bltin; /* zap builtins */
7815 if (builtinloc >= 0 && idx_bltin < 0)
7816 firstchange = 0;
7817 clearcmdentry(firstchange);
7818 builtinloc = idx_bltin;
7819}
Ron Yorston95ebcf72015-11-03 09:42:23 +00007820enum {
7821 TEOF,
7822 TNL,
7823 TREDIR,
7824 TWORD,
7825 TSEMI,
7826 TBACKGND,
7827 TAND,
7828 TOR,
7829 TPIPE,
7830 TLP,
7831 TRP,
7832 TENDCASE,
7833 TENDBQUOTE,
7834 TNOT,
7835 TCASE,
7836 TDO,
7837 TDONE,
7838 TELIF,
7839 TELSE,
7840 TESAC,
7841 TFI,
7842 TFOR,
7843#if ENABLE_ASH_BASH_COMPAT
7844 TFUNCTION,
7845#endif
7846 TIF,
7847 TIN,
7848 TTHEN,
7849 TUNTIL,
7850 TWHILE,
7851 TBEGIN,
7852 TEND
7853};
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007854typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007855
7856/* first char is indicating which tokens mark the end of a list */
7857static const char *const tokname_array[] = {
7858 "\1end of file",
7859 "\0newline",
7860 "\0redirection",
7861 "\0word",
7862 "\0;",
7863 "\0&",
7864 "\0&&",
7865 "\0||",
7866 "\0|",
7867 "\0(",
7868 "\1)",
7869 "\1;;",
7870 "\1`",
7871#define KWDOFFSET 13
7872 /* the following are keywords */
7873 "\0!",
7874 "\0case",
7875 "\1do",
7876 "\1done",
7877 "\1elif",
7878 "\1else",
7879 "\1esac",
7880 "\1fi",
7881 "\0for",
Ron Yorston95ebcf72015-11-03 09:42:23 +00007882#if ENABLE_ASH_BASH_COMPAT
7883 "\0function",
7884#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007885 "\0if",
7886 "\0in",
7887 "\1then",
7888 "\0until",
7889 "\0while",
7890 "\0{",
7891 "\1}",
7892};
7893
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007894/* Wrapper around strcmp for qsort/bsearch/... */
7895static int
7896pstrcmp(const void *a, const void *b)
7897{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007898 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007899}
7900
7901static const char *const *
7902findkwd(const char *s)
7903{
7904 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007905 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7906 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007907}
7908
7909/*
7910 * Locate and print what a word is...
7911 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007912static int
Ron Yorston3f221112015-08-03 13:47:33 +01007913describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007914{
7915 struct cmdentry entry;
7916 struct tblentry *cmdp;
7917#if ENABLE_ASH_ALIAS
7918 const struct alias *ap;
7919#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007920
7921 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007922
7923 if (describe_command_verbose) {
7924 out1str(command);
7925 }
7926
7927 /* First look at the keywords */
7928 if (findkwd(command)) {
7929 out1str(describe_command_verbose ? " is a shell keyword" : command);
7930 goto out;
7931 }
7932
7933#if ENABLE_ASH_ALIAS
7934 /* Then look at the aliases */
7935 ap = lookupalias(command, 0);
7936 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007937 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007938 out1str("alias ");
7939 printalias(ap);
7940 return 0;
7941 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007942 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007943 goto out;
7944 }
7945#endif
7946 /* Then check if it is a tracked alias */
7947 cmdp = cmdlookup(command, 0);
7948 if (cmdp != NULL) {
7949 entry.cmdtype = cmdp->cmdtype;
7950 entry.u = cmdp->param;
7951 } else {
7952 /* Finally use brute force */
7953 find_command(command, &entry, DO_ABS, path);
7954 }
7955
7956 switch (entry.cmdtype) {
7957 case CMDNORMAL: {
7958 int j = entry.u.index;
7959 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007960 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007961 p = command;
7962 } else {
7963 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007964 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007965 stunalloc(p);
7966 } while (--j >= 0);
7967 }
7968 if (describe_command_verbose) {
7969 out1fmt(" is%s %s",
7970 (cmdp ? " a tracked alias for" : nullstr), p
7971 );
7972 } else {
7973 out1str(p);
7974 }
7975 break;
7976 }
7977
7978 case CMDFUNCTION:
7979 if (describe_command_verbose) {
7980 out1str(" is a shell function");
7981 } else {
7982 out1str(command);
7983 }
7984 break;
7985
7986 case CMDBUILTIN:
7987 if (describe_command_verbose) {
7988 out1fmt(" is a %sshell builtin",
7989 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7990 "special " : nullstr
7991 );
7992 } else {
7993 out1str(command);
7994 }
7995 break;
7996
7997 default:
7998 if (describe_command_verbose) {
7999 out1str(": not found\n");
8000 }
8001 return 127;
8002 }
8003 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01008004 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008005 return 0;
8006}
8007
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008008static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008009typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008010{
Denis Vlasenko46846e22007-05-20 13:08:31 +00008011 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008012 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00008013 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008014
Denis Vlasenko46846e22007-05-20 13:08:31 +00008015 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00008016 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00008017 i++;
8018 verbose = 0;
8019 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00008020 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01008021 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008022 }
8023 return err;
8024}
8025
8026#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008027static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008028commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008029{
8030 int c;
8031 enum {
8032 VERIFY_BRIEF = 1,
8033 VERIFY_VERBOSE = 2,
8034 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01008035 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008036
8037 while ((c = nextopt("pvV")) != '\0')
8038 if (c == 'V')
8039 verify |= VERIFY_VERBOSE;
8040 else if (c == 'v')
8041 verify |= VERIFY_BRIEF;
8042#if DEBUG
8043 else if (c != 'p')
8044 abort();
8045#endif
Ron Yorston3f221112015-08-03 13:47:33 +01008046 else
8047 path = bb_default_path;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008048 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8049 if (verify && (*argptr != NULL)) {
Ron Yorston3f221112015-08-03 13:47:33 +01008050 return describe_command(*argptr, path, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008051 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008052
8053 return 0;
8054}
8055#endif
8056
8057
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008058/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00008059
Denis Vlasenko340299a2008-11-21 10:36:36 +00008060static int funcblocksize; /* size of structures in function */
8061static int funcstringsize; /* size of strings in node */
8062static void *funcblock; /* block to allocate function from */
8063static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008064
Eric Andersencb57d552001-06-28 07:25:16 +00008065/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008066#define EV_EXIT 01 /* exit after evaluating tree */
8067#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersencb57d552001-06-28 07:25:16 +00008068
Denys Vlasenko3e134eb2016-04-22 18:09:21 +02008069static const uint8_t nodesize[N_NUMBER] ALIGN1 = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008070 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8071 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8072 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8073 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8074 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8075 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8076 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8077 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8078 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8079 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8080 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8081 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8082 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8083 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8084 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8085 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8086 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008087#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008088 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008089#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008090 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8091 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8092 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8093 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8094 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8095 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8096 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8097 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8098 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008099};
8100
8101static void calcsize(union node *n);
8102
8103static void
8104sizenodelist(struct nodelist *lp)
8105{
8106 while (lp) {
8107 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8108 calcsize(lp->n);
8109 lp = lp->next;
8110 }
8111}
8112
8113static void
8114calcsize(union node *n)
8115{
8116 if (n == NULL)
8117 return;
8118 funcblocksize += nodesize[n->type];
8119 switch (n->type) {
8120 case NCMD:
8121 calcsize(n->ncmd.redirect);
8122 calcsize(n->ncmd.args);
8123 calcsize(n->ncmd.assign);
8124 break;
8125 case NPIPE:
8126 sizenodelist(n->npipe.cmdlist);
8127 break;
8128 case NREDIR:
8129 case NBACKGND:
8130 case NSUBSHELL:
8131 calcsize(n->nredir.redirect);
8132 calcsize(n->nredir.n);
8133 break;
8134 case NAND:
8135 case NOR:
8136 case NSEMI:
8137 case NWHILE:
8138 case NUNTIL:
8139 calcsize(n->nbinary.ch2);
8140 calcsize(n->nbinary.ch1);
8141 break;
8142 case NIF:
8143 calcsize(n->nif.elsepart);
8144 calcsize(n->nif.ifpart);
8145 calcsize(n->nif.test);
8146 break;
8147 case NFOR:
8148 funcstringsize += strlen(n->nfor.var) + 1;
8149 calcsize(n->nfor.body);
8150 calcsize(n->nfor.args);
8151 break;
8152 case NCASE:
8153 calcsize(n->ncase.cases);
8154 calcsize(n->ncase.expr);
8155 break;
8156 case NCLIST:
8157 calcsize(n->nclist.body);
8158 calcsize(n->nclist.pattern);
8159 calcsize(n->nclist.next);
8160 break;
8161 case NDEFUN:
8162 case NARG:
8163 sizenodelist(n->narg.backquote);
8164 funcstringsize += strlen(n->narg.text) + 1;
8165 calcsize(n->narg.next);
8166 break;
8167 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008168#if ENABLE_ASH_BASH_COMPAT
8169 case NTO2:
8170#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008171 case NCLOBBER:
8172 case NFROM:
8173 case NFROMTO:
8174 case NAPPEND:
8175 calcsize(n->nfile.fname);
8176 calcsize(n->nfile.next);
8177 break;
8178 case NTOFD:
8179 case NFROMFD:
8180 calcsize(n->ndup.vname);
8181 calcsize(n->ndup.next);
8182 break;
8183 case NHERE:
8184 case NXHERE:
8185 calcsize(n->nhere.doc);
8186 calcsize(n->nhere.next);
8187 break;
8188 case NNOT:
8189 calcsize(n->nnot.com);
8190 break;
8191 };
8192}
8193
8194static char *
8195nodeckstrdup(char *s)
8196{
8197 char *rtn = funcstring;
8198
8199 strcpy(funcstring, s);
8200 funcstring += strlen(s) + 1;
8201 return rtn;
8202}
8203
8204static union node *copynode(union node *);
8205
8206static struct nodelist *
8207copynodelist(struct nodelist *lp)
8208{
8209 struct nodelist *start;
8210 struct nodelist **lpp;
8211
8212 lpp = &start;
8213 while (lp) {
8214 *lpp = funcblock;
8215 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8216 (*lpp)->n = copynode(lp->n);
8217 lp = lp->next;
8218 lpp = &(*lpp)->next;
8219 }
8220 *lpp = NULL;
8221 return start;
8222}
8223
8224static union node *
8225copynode(union node *n)
8226{
8227 union node *new;
8228
8229 if (n == NULL)
8230 return NULL;
8231 new = funcblock;
8232 funcblock = (char *) funcblock + nodesize[n->type];
8233
8234 switch (n->type) {
8235 case NCMD:
8236 new->ncmd.redirect = copynode(n->ncmd.redirect);
8237 new->ncmd.args = copynode(n->ncmd.args);
8238 new->ncmd.assign = copynode(n->ncmd.assign);
8239 break;
8240 case NPIPE:
8241 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008242 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008243 break;
8244 case NREDIR:
8245 case NBACKGND:
8246 case NSUBSHELL:
8247 new->nredir.redirect = copynode(n->nredir.redirect);
8248 new->nredir.n = copynode(n->nredir.n);
8249 break;
8250 case NAND:
8251 case NOR:
8252 case NSEMI:
8253 case NWHILE:
8254 case NUNTIL:
8255 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8256 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8257 break;
8258 case NIF:
8259 new->nif.elsepart = copynode(n->nif.elsepart);
8260 new->nif.ifpart = copynode(n->nif.ifpart);
8261 new->nif.test = copynode(n->nif.test);
8262 break;
8263 case NFOR:
8264 new->nfor.var = nodeckstrdup(n->nfor.var);
8265 new->nfor.body = copynode(n->nfor.body);
8266 new->nfor.args = copynode(n->nfor.args);
8267 break;
8268 case NCASE:
8269 new->ncase.cases = copynode(n->ncase.cases);
8270 new->ncase.expr = copynode(n->ncase.expr);
8271 break;
8272 case NCLIST:
8273 new->nclist.body = copynode(n->nclist.body);
8274 new->nclist.pattern = copynode(n->nclist.pattern);
8275 new->nclist.next = copynode(n->nclist.next);
8276 break;
8277 case NDEFUN:
8278 case NARG:
8279 new->narg.backquote = copynodelist(n->narg.backquote);
8280 new->narg.text = nodeckstrdup(n->narg.text);
8281 new->narg.next = copynode(n->narg.next);
8282 break;
8283 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008284#if ENABLE_ASH_BASH_COMPAT
8285 case NTO2:
8286#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008287 case NCLOBBER:
8288 case NFROM:
8289 case NFROMTO:
8290 case NAPPEND:
8291 new->nfile.fname = copynode(n->nfile.fname);
8292 new->nfile.fd = n->nfile.fd;
8293 new->nfile.next = copynode(n->nfile.next);
8294 break;
8295 case NTOFD:
8296 case NFROMFD:
8297 new->ndup.vname = copynode(n->ndup.vname);
8298 new->ndup.dupfd = n->ndup.dupfd;
8299 new->ndup.fd = n->ndup.fd;
8300 new->ndup.next = copynode(n->ndup.next);
8301 break;
8302 case NHERE:
8303 case NXHERE:
8304 new->nhere.doc = copynode(n->nhere.doc);
8305 new->nhere.fd = n->nhere.fd;
8306 new->nhere.next = copynode(n->nhere.next);
8307 break;
8308 case NNOT:
8309 new->nnot.com = copynode(n->nnot.com);
8310 break;
8311 };
8312 new->type = n->type;
8313 return new;
8314}
8315
8316/*
8317 * Make a copy of a parse tree.
8318 */
8319static struct funcnode *
8320copyfunc(union node *n)
8321{
8322 struct funcnode *f;
8323 size_t blocksize;
8324
8325 funcblocksize = offsetof(struct funcnode, n);
8326 funcstringsize = 0;
8327 calcsize(n);
8328 blocksize = funcblocksize;
8329 f = ckmalloc(blocksize + funcstringsize);
8330 funcblock = (char *) f + offsetof(struct funcnode, n);
8331 funcstring = (char *) f + blocksize;
8332 copynode(n);
8333 f->count = 0;
8334 return f;
8335}
8336
8337/*
8338 * Define a shell function.
8339 */
8340static void
8341defun(char *name, union node *func)
8342{
8343 struct cmdentry entry;
8344
8345 INT_OFF;
8346 entry.cmdtype = CMDFUNCTION;
8347 entry.u.func = copyfunc(func);
8348 addcmdentry(name, &entry);
8349 INT_ON;
8350}
8351
Denis Vlasenko4b875702009-03-19 13:30:04 +00008352/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008353#define SKIPBREAK (1 << 0)
8354#define SKIPCONT (1 << 1)
8355#define SKIPFUNC (1 << 2)
8356#define SKIPFILE (1 << 3)
8357#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008358static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008359static int skipcount; /* number of levels to skip */
8360static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008361static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008362
Denis Vlasenko4b875702009-03-19 13:30:04 +00008363/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008364static int evalstring(char *s, int mask);
8365
Denis Vlasenko4b875702009-03-19 13:30:04 +00008366/* Called to execute a trap.
8367 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008368 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008369 *
8370 * Perhaps we should avoid entering new trap handlers
8371 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008372 */
8373static int
8374dotrap(void)
8375{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008376 uint8_t *g;
8377 int sig;
8378 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008379
8380 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008381 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008382 xbarrier();
8383
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008384 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008385 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
Denis Vlasenko4b875702009-03-19 13:30:04 +00008386 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008387
Denis Vlasenko4b875702009-03-19 13:30:04 +00008388 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008389 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008390 t = trap[sig];
8391 /* non-trapped SIGINT is handled separately by raise_interrupt,
8392 * don't upset it by resetting gotsig[SIGINT-1] */
8393 if (sig == SIGINT && !t)
8394 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008395
8396 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008397 *g = 0;
8398 if (!t)
8399 continue;
Denys Vlasenko928e2a72016-09-29 00:30:31 +02008400 evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008401 exitstatus = savestatus;
Denys Vlasenko928e2a72016-09-29 00:30:31 +02008402 if (evalskip) {
8403 TRACE(("dotrap returns %d\n", evalskip));
8404 return evalskip;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008405 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008406 }
8407
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008408 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008409 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008410}
8411
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008412/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008413static int evalloop(union node *, int);
8414static int evalfor(union node *, int);
8415static int evalcase(union node *, int);
8416static int evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008417static void expredir(union node *);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008418static int evalpipe(union node *, int);
8419static int evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008420static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008421static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008422
Eric Andersen62483552001-07-10 06:09:16 +00008423/*
Eric Andersenc470f442003-07-28 09:56:35 +00008424 * Evaluate a parse tree. The value is left in the global variable
8425 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008426 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008427static int
Eric Andersenc470f442003-07-28 09:56:35 +00008428evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008429{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008430 struct jmploc *volatile savehandler = exception_handler;
8431 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008432 int checkexit = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008433 int (*evalfn)(union node *, int);
8434 int status = 0;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008435 int int_level;
8436
8437 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008438
Eric Andersenc470f442003-07-28 09:56:35 +00008439 if (n == NULL) {
8440 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008441 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008442 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008443 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008444
8445 exception_handler = &jmploc;
8446 {
8447 int err = setjmp(jmploc.loc);
8448 if (err) {
8449 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008450 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008451 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8452 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008453 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008454 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008455 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008456 TRACE(("exception %d in evaltree, propagating err=%d\n",
8457 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008458 exception_handler = savehandler;
8459 longjmp(exception_handler->loc, err);
8460 }
8461 }
8462
Eric Andersenc470f442003-07-28 09:56:35 +00008463 switch (n->type) {
8464 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008465#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008466 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008467 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008468 break;
8469#endif
8470 case NNOT:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008471 status = !evaltree(n->nnot.com, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008472 goto setstatus;
8473 case NREDIR:
8474 expredir(n->nredir.redirect);
8475 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8476 if (!status) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008477 status = evaltree(n->nredir.n, flags & EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008478 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008479 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008480 goto setstatus;
8481 case NCMD:
8482 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008483 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008484 if (eflag && !(flags & EV_TESTED))
8485 checkexit = ~0;
8486 goto calleval;
8487 case NFOR:
8488 evalfn = evalfor;
8489 goto calleval;
8490 case NWHILE:
8491 case NUNTIL:
8492 evalfn = evalloop;
8493 goto calleval;
8494 case NSUBSHELL:
Rostislav Skudnov204c7fb2016-09-16 19:04:02 +00008495 evalfn = evalsubshell;
8496 goto checkexit;
Eric Andersenc470f442003-07-28 09:56:35 +00008497 case NBACKGND:
8498 evalfn = evalsubshell;
8499 goto calleval;
8500 case NPIPE:
8501 evalfn = evalpipe;
8502 goto checkexit;
8503 case NCASE:
8504 evalfn = evalcase;
8505 goto calleval;
8506 case NAND:
8507 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008508 case NSEMI: {
8509
Eric Andersenc470f442003-07-28 09:56:35 +00008510#if NAND + 1 != NOR
8511#error NAND + 1 != NOR
8512#endif
8513#if NOR + 1 != NSEMI
8514#error NOR + 1 != NSEMI
8515#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008516 unsigned is_or = n->type - NAND;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008517 status = evaltree(
Eric Andersenc470f442003-07-28 09:56:35 +00008518 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008519 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008520 );
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008521 if (!status == is_or || evalskip)
Eric Andersenc470f442003-07-28 09:56:35 +00008522 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008523 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008524 evaln:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008525 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008526 calleval:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008527 status = evalfn(n, flags);
8528 goto setstatus;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008529 }
Eric Andersenc470f442003-07-28 09:56:35 +00008530 case NIF:
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008531 status = evaltree(n->nif.test, EV_TESTED);
Eric Andersenc470f442003-07-28 09:56:35 +00008532 if (evalskip)
8533 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008534 if (!status) {
Eric Andersenc470f442003-07-28 09:56:35 +00008535 n = n->nif.ifpart;
8536 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008537 }
8538 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008539 n = n->nif.elsepart;
8540 goto evaln;
8541 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008542 status = 0;
8543 goto setstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00008544 case NDEFUN:
8545 defun(n->narg.text, n->narg.next);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008546 /* Not necessary. To test it:
8547 * "false; f() { qwerty; }; echo $?" should print 0.
8548 */
8549 /* status = 0; */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008550 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008551 exitstatus = status;
8552 break;
8553 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008554
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008555 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008556 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008557
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008558 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008559 /* Order of checks below is important:
8560 * signal handlers trigger before exit caused by "set -e".
8561 */
8562 if (pending_sig && dotrap())
8563 goto exexit;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008564 if (checkexit & status)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008565 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008566
8567 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008568 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008569 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008570 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008571
8572 RESTORE_INT(int_level);
8573 TRACE(("leaving evaltree (no interrupts)\n"));
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008574
8575 return exitstatus;
Eric Andersen62483552001-07-10 06:09:16 +00008576}
8577
Eric Andersenc470f442003-07-28 09:56:35 +00008578#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8579static
8580#endif
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008581int evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
Eric Andersenc470f442003-07-28 09:56:35 +00008582
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008583static int
Eric Andersenc470f442003-07-28 09:56:35 +00008584evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008585{
8586 int status;
8587
8588 loopnest++;
8589 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008590 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008591 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008592 int i;
8593
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008594 i = evaltree(n->nbinary.ch1, EV_TESTED);
Eric Andersencb57d552001-06-28 07:25:16 +00008595 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008596 skipping:
8597 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008598 evalskip = 0;
8599 continue;
8600 }
8601 if (evalskip == SKIPBREAK && --skipcount <= 0)
8602 evalskip = 0;
8603 break;
8604 }
Eric Andersenc470f442003-07-28 09:56:35 +00008605 if (n->type != NWHILE)
8606 i = !i;
8607 if (i != 0)
8608 break;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008609 status = evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008610 if (evalskip)
8611 goto skipping;
8612 }
Eric Andersencb57d552001-06-28 07:25:16 +00008613 exitstatus = status;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008614 loopnest--;
8615
8616 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008617}
8618
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008619static int
Eric Andersenc470f442003-07-28 09:56:35 +00008620evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008621{
8622 struct arglist arglist;
8623 union node *argp;
8624 struct strlist *sp;
8625 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008626 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008627
8628 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008629 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008630 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008631 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008632 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008633 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008634 if (evalskip)
8635 goto out;
8636 }
8637 *arglist.lastp = NULL;
8638
Eric Andersencb57d552001-06-28 07:25:16 +00008639 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008640 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008641 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008642 setvar0(n->nfor.var, sp->text);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008643 status = evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008644 if (evalskip) {
8645 if (evalskip == SKIPCONT && --skipcount <= 0) {
8646 evalskip = 0;
8647 continue;
8648 }
8649 if (evalskip == SKIPBREAK && --skipcount <= 0)
8650 evalskip = 0;
8651 break;
8652 }
8653 }
8654 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008655 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008656 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008657
8658 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008659}
8660
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008661static int
Eric Andersenc470f442003-07-28 09:56:35 +00008662evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008663{
8664 union node *cp;
8665 union node *patp;
8666 struct arglist arglist;
8667 struct stackmark smark;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008668 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008669
8670 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008671 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008672 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008673 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008674 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8675 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008676 if (casematch(patp, arglist.list->text)) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008677 /* Ensure body is non-empty as otherwise
8678 * EV_EXIT may prevent us from setting the
8679 * exit status.
8680 */
8681 if (evalskip == 0 && cp->nclist.body) {
8682 status = evaltree(cp->nclist.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008683 }
8684 goto out;
8685 }
8686 }
8687 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008688 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008689 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008690
8691 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008692}
8693
Eric Andersenc470f442003-07-28 09:56:35 +00008694/*
8695 * Kick off a subshell to evaluate a tree.
8696 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008697static int
Eric Andersenc470f442003-07-28 09:56:35 +00008698evalsubshell(union node *n, int flags)
8699{
8700 struct job *jp;
8701 int backgnd = (n->type == NBACKGND);
8702 int status;
8703
8704 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008705 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008706 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008707 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008708 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008709 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008710 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008711 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008712 flags |= EV_EXIT;
8713 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008714 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008715 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008716 redirect(n->nredir.redirect, 0);
8717 evaltreenr(n->nredir.n, flags);
8718 /* never returns */
8719 }
8720 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008721 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008722 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00008723 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008724 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00008725}
8726
Eric Andersenc470f442003-07-28 09:56:35 +00008727/*
8728 * Compute the names of the files in a redirection list.
8729 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008730static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008731static void
8732expredir(union node *n)
8733{
8734 union node *redir;
8735
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008736 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008737 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008738
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008739 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008740 fn.lastp = &fn.list;
8741 switch (redir->type) {
8742 case NFROMTO:
8743 case NFROM:
8744 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008745#if ENABLE_ASH_BASH_COMPAT
8746 case NTO2:
8747#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008748 case NCLOBBER:
8749 case NAPPEND:
8750 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008751 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008752#if ENABLE_ASH_BASH_COMPAT
8753 store_expfname:
8754#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008755#if 0
8756// By the design of stack allocator, the loop of this kind:
8757// while true; do while true; do break; done </dev/null; done
8758// will look like a memory leak: ash plans to free expfname's
8759// of "/dev/null" as soon as it finishes running the loop
8760// (in this case, never).
8761// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008762 if (redir->nfile.expfname)
8763 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008764// It results in corrupted state of stacked allocations.
8765#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008766 redir->nfile.expfname = fn.list->text;
8767 break;
8768 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008769 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008770 if (redir->ndup.vname) {
8771 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008772 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008773 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008774#if ENABLE_ASH_BASH_COMPAT
8775//FIXME: we used expandarg with different args!
8776 if (!isdigit_str9(fn.list->text)) {
8777 /* >&file, not >&fd */
8778 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8779 ash_msg_and_raise_error("redir error");
8780 redir->type = NTO2;
8781 goto store_expfname;
8782 }
8783#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008784 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008785 }
8786 break;
8787 }
8788 }
8789}
8790
Eric Andersencb57d552001-06-28 07:25:16 +00008791/*
Eric Andersencb57d552001-06-28 07:25:16 +00008792 * Evaluate a pipeline. All the processes in the pipeline are children
8793 * of the process creating the pipeline. (This differs from some versions
8794 * of the shell, which make the last process in a pipeline the parent
8795 * of all the rest.)
8796 */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008797static int
Eric Andersenc470f442003-07-28 09:56:35 +00008798evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008799{
8800 struct job *jp;
8801 struct nodelist *lp;
8802 int pipelen;
8803 int prevfd;
8804 int pip[2];
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008805 int status = 0;
Eric Andersencb57d552001-06-28 07:25:16 +00008806
Eric Andersenc470f442003-07-28 09:56:35 +00008807 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008808 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008809 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008810 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008811 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008812 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008813 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008814 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008815 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008816 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008817 pip[1] = -1;
8818 if (lp->next) {
8819 if (pipe(pip) < 0) {
8820 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008821 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008822 }
8823 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008824 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008825 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008826 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008827 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008828 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008829 if (prevfd > 0) {
8830 dup2(prevfd, 0);
8831 close(prevfd);
8832 }
8833 if (pip[1] > 1) {
8834 dup2(pip[1], 1);
8835 close(pip[1]);
8836 }
Eric Andersenc470f442003-07-28 09:56:35 +00008837 evaltreenr(lp->n, flags);
8838 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008839 }
8840 if (prevfd >= 0)
8841 close(prevfd);
8842 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008843 /* Don't want to trigger debugging */
8844 if (pip[1] != -1)
8845 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008846 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008847 if (n->npipe.pipe_backgnd == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008848 status = waitforjob(jp);
8849 TRACE(("evalpipe: job done exit status %d\n", status));
Eric Andersencb57d552001-06-28 07:25:16 +00008850 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008851 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02008852
8853 return status;
Eric Andersencb57d552001-06-28 07:25:16 +00008854}
8855
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008856/*
8857 * Controls whether the shell is interactive or not.
8858 */
8859static void
8860setinteractive(int on)
8861{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008862 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008863
8864 if (++on == is_interactive)
8865 return;
8866 is_interactive = on;
8867 setsignal(SIGINT);
8868 setsignal(SIGQUIT);
8869 setsignal(SIGTERM);
8870#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8871 if (is_interactive > 1) {
8872 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008873 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008874
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008875 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008876 /* note: ash and hush share this string */
8877 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008878 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8879 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008880 bb_banner,
8881 "built-in shell (ash)"
8882 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008883 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008884 }
8885 }
8886#endif
8887}
8888
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008889static void
8890optschanged(void)
8891{
8892#if DEBUG
8893 opentrace();
8894#endif
8895 setinteractive(iflag);
8896 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008897#if ENABLE_FEATURE_EDITING_VI
8898 if (viflag)
8899 line_input_state->flags |= VI_MODE;
8900 else
8901 line_input_state->flags &= ~VI_MODE;
8902#else
8903 viflag = 0; /* forcibly keep the option off */
8904#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008905}
8906
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008907static struct localvar *localvars;
8908
8909/*
8910 * Called after a function returns.
8911 * Interrupts must be off.
8912 */
8913static void
8914poplocalvars(void)
8915{
8916 struct localvar *lvp;
8917 struct var *vp;
8918
8919 while ((lvp = localvars) != NULL) {
8920 localvars = lvp->next;
8921 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008922 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008923 if (vp == NULL) { /* $- saved */
8924 memcpy(optlist, lvp->text, sizeof(optlist));
8925 free((char*)lvp->text);
8926 optschanged();
8927 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008928 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008929 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008930 if (vp->var_func)
8931 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008932 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008933 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008934 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008935 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008936 }
8937 free(lvp);
8938 }
8939}
8940
8941static int
8942evalfun(struct funcnode *func, int argc, char **argv, int flags)
8943{
8944 volatile struct shparam saveparam;
8945 struct localvar *volatile savelocalvars;
8946 struct jmploc *volatile savehandler;
8947 struct jmploc jmploc;
8948 int e;
8949
8950 saveparam = shellparam;
8951 savelocalvars = localvars;
8952 e = setjmp(jmploc.loc);
8953 if (e) {
8954 goto funcdone;
8955 }
8956 INT_OFF;
8957 savehandler = exception_handler;
8958 exception_handler = &jmploc;
8959 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008960 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008961 func->count++;
8962 funcnest++;
8963 INT_ON;
8964 shellparam.nparam = argc - 1;
8965 shellparam.p = argv + 1;
8966#if ENABLE_ASH_GETOPTS
8967 shellparam.optind = 1;
8968 shellparam.optoff = -1;
8969#endif
8970 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008971 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008972 INT_OFF;
8973 funcnest--;
8974 freefunc(func);
8975 poplocalvars();
8976 localvars = savelocalvars;
8977 freeparam(&shellparam);
8978 shellparam = saveparam;
8979 exception_handler = savehandler;
8980 INT_ON;
8981 evalskip &= ~SKIPFUNC;
8982 return e;
8983}
8984
Denis Vlasenko131ae172007-02-18 13:00:19 +00008985#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008986static char **
8987parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008988{
8989 char *cp, c;
8990
8991 for (;;) {
8992 cp = *++argv;
8993 if (!cp)
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008994 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008995 if (*cp++ != '-')
8996 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008997 c = *cp++;
8998 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008999 break;
9000 if (c == '-' && !*cp) {
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01009001 if (!*++argv)
9002 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009003 break;
9004 }
9005 do {
9006 switch (c) {
9007 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00009008 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00009009 break;
9010 default:
9011 /* run 'typecmd' for other options */
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01009012 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00009013 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00009014 c = *cp++;
9015 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00009016 }
9017 return argv;
9018}
9019#endif
9020
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009021/*
9022 * Make a variable a local variable. When a variable is made local, it's
9023 * value and flags are saved in a localvar structure. The saved values
9024 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02009025 * "-" as a special case: it makes changes to "set +-options" local
9026 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009027 */
9028static void
9029mklocal(char *name)
9030{
9031 struct localvar *lvp;
9032 struct var **vpp;
9033 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009034 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009035
9036 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009037 /* Cater for duplicate "local". Examples:
9038 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
9039 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
9040 */
9041 lvp = localvars;
9042 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02009043 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009044 if (eq)
9045 setvareq(name, 0);
9046 /* else:
9047 * it's a duplicate "local VAR" declaration, do nothing
9048 */
9049 return;
9050 }
9051 lvp = lvp->next;
9052 }
9053
9054 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009055 if (LONE_DASH(name)) {
9056 char *p;
9057 p = ckmalloc(sizeof(optlist));
9058 lvp->text = memcpy(p, optlist, sizeof(optlist));
9059 vp = NULL;
9060 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009061 vpp = hashvar(name);
9062 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009063 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009064 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009065 if (eq)
9066 setvareq(name, VSTRFIXED);
9067 else
9068 setvar(name, NULL, VSTRFIXED);
9069 vp = *vpp; /* the new variable */
9070 lvp->flags = VUNSET;
9071 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009072 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009073 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009074 /* make sure neither "struct var" nor string gets freed
9075 * during (un)setting:
9076 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009077 vp->flags |= VSTRFIXED|VTEXTFIXED;
9078 if (eq)
9079 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009080 else
9081 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009082 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009083 }
9084 }
9085 lvp->vp = vp;
9086 lvp->next = localvars;
9087 localvars = lvp;
9088 INT_ON;
9089}
9090
9091/*
9092 * The "local" command.
9093 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009094static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009095localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009096{
9097 char *name;
9098
Ron Yorstonef2386b2015-10-29 16:19:14 +00009099 if (!funcnest)
9100 ash_msg_and_raise_error("not in a function");
9101
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009102 argv = argptr;
9103 while ((name = *argv++) != NULL) {
9104 mklocal(name);
9105 }
9106 return 0;
9107}
9108
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009109static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009110falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009111{
9112 return 1;
9113}
9114
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009115static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009116truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009117{
9118 return 0;
9119}
9120
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009121static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009122execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009123{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009124 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009125 iflag = 0; /* exit on error */
9126 mflag = 0;
9127 optschanged();
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009128 /* We should set up signals for "exec CMD"
9129 * the same way as for "CMD" without "exec".
9130 * But optschanged->setinteractive->setsignal
9131 * still thought we are a root shell. Therefore, for example,
9132 * SIGQUIT is still set to IGN. Fix it:
9133 */
9134 shlvl++;
9135 setsignal(SIGQUIT);
9136 /*setsignal(SIGTERM); - unnecessary because of iflag=0 */
9137 /*setsignal(SIGTSTP); - unnecessary because of mflag=0 */
9138 /*setsignal(SIGTTOU); - unnecessary because of mflag=0 */
9139
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009140 shellexec(argv + 1, pathval(), 0);
Denys Vlasenkoe5814a52016-07-16 18:33:55 +02009141 /* NOTREACHED */
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009142 }
9143 return 0;
9144}
9145
9146/*
9147 * The return command.
9148 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009149static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009150returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009151{
9152 /*
9153 * If called outside a function, do what ksh does;
9154 * skip the rest of the file.
9155 */
9156 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9157 return argv[1] ? number(argv[1]) : exitstatus;
9158}
9159
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009160/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009161static int breakcmd(int, char **) FAST_FUNC;
9162static int dotcmd(int, char **) FAST_FUNC;
9163static int evalcmd(int, char **) FAST_FUNC;
9164static int exitcmd(int, char **) FAST_FUNC;
9165static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009166#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009167static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009168#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009169#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009170static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009171#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009172#if MAX_HISTORY
9173static int historycmd(int, char **) FAST_FUNC;
9174#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009175#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009176static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009177#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009178static int readcmd(int, char **) FAST_FUNC;
9179static int setcmd(int, char **) FAST_FUNC;
9180static int shiftcmd(int, char **) FAST_FUNC;
9181static int timescmd(int, char **) FAST_FUNC;
9182static int trapcmd(int, char **) FAST_FUNC;
9183static int umaskcmd(int, char **) FAST_FUNC;
9184static int unsetcmd(int, char **) FAST_FUNC;
9185static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009186
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009187#define BUILTIN_NOSPEC "0"
9188#define BUILTIN_SPECIAL "1"
9189#define BUILTIN_REGULAR "2"
9190#define BUILTIN_SPEC_REG "3"
9191#define BUILTIN_ASSIGN "4"
9192#define BUILTIN_SPEC_ASSG "5"
9193#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009194#define BUILTIN_SPEC_REG_ASSG "7"
9195
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009196/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009197#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009198static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009199#endif
9200#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009201static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009202#endif
9203#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009204static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009205#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009206
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009207/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009208static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009209 { BUILTIN_SPEC_REG "." , dotcmd },
9210 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009211#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009212 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009213#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009214 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009215#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009216#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009217#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009218 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009219#endif
9220#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009221 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009222#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009223 { BUILTIN_SPEC_REG "break" , breakcmd },
9224 { BUILTIN_REGULAR "cd" , cdcmd },
9225 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009226#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009227 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009228#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009229 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009230#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009231 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009232#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009233 { BUILTIN_SPEC_REG "eval" , evalcmd },
9234 { BUILTIN_SPEC_REG "exec" , execcmd },
9235 { BUILTIN_SPEC_REG "exit" , exitcmd },
9236 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9237 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009238#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009239 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009240#endif
9241#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009242 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009243#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009244 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009245#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009246 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009247#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009248#if MAX_HISTORY
9249 { BUILTIN_NOSPEC "history" , historycmd },
9250#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009251#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009252 { BUILTIN_REGULAR "jobs" , jobscmd },
9253 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009254#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009255#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009256 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009257#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009258 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009259#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009260 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009261#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009262 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9263 { BUILTIN_REGULAR "read" , readcmd },
9264 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9265 { BUILTIN_SPEC_REG "return" , returncmd },
9266 { BUILTIN_SPEC_REG "set" , setcmd },
9267 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009268#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009269 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009270#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009271#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009272 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009273#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009274 { BUILTIN_SPEC_REG "times" , timescmd },
9275 { BUILTIN_SPEC_REG "trap" , trapcmd },
9276 { BUILTIN_REGULAR "true" , truecmd },
9277 { BUILTIN_NOSPEC "type" , typecmd },
9278 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9279 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009280#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009281 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009282#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009283 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9284 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009285};
9286
Denis Vlasenko80591b02008-03-25 07:49:43 +00009287/* Should match the above table! */
9288#define COMMANDCMD (builtintab + \
Denys Vlasenko928e2a72016-09-29 00:30:31 +02009289 /* . : */ 2 + \
9290 /* [ */ 1 * ENABLE_ASH_BUILTIN_TEST + \
9291 /* [[ */ 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9292 /* alias */ 1 * ENABLE_ASH_ALIAS + \
9293 /* bg */ 1 * ENABLE_ASH_JOB_CONTROL + \
9294 /* break cd cddir */ 3)
9295#define EVALCMD (COMMANDCMD + \
9296 /* command */ 1 * ENABLE_ASH_CMDCMD + \
9297 /* continue */ 1 + \
9298 /* echo */ 1 * ENABLE_ASH_BUILTIN_ECHO + \
9299 0)
9300#define EXECCMD (EVALCMD + \
9301 /* eval */ 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009302
9303/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009304 * Search the table of builtin commands.
9305 */
9306static struct builtincmd *
9307find_builtin(const char *name)
9308{
9309 struct builtincmd *bp;
9310
9311 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009312 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009313 pstrcmp
9314 );
9315 return bp;
9316}
9317
9318/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009319 * Execute a simple command.
9320 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009321static int
9322isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009323{
9324 const char *q = endofname(p);
9325 if (p == q)
9326 return 0;
9327 return *q == '=';
9328}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009329static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009330bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009331{
9332 /* Preserve exitstatus of a previous possible redirection
9333 * as POSIX mandates */
9334 return back_exitstatus;
9335}
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009336static int
Eric Andersenc470f442003-07-28 09:56:35 +00009337evalcommand(union node *cmd, int flags)
9338{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009339 static const struct builtincmd null_bltin = {
9340 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009341 };
Eric Andersenc470f442003-07-28 09:56:35 +00009342 struct stackmark smark;
9343 union node *argp;
9344 struct arglist arglist;
9345 struct arglist varlist;
9346 char **argv;
9347 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009348 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009349 struct cmdentry cmdentry;
9350 struct job *jp;
9351 char *lastarg;
9352 const char *path;
9353 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009354 int status;
9355 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009356 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009357 smallint cmd_is_exec;
9358 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009359
9360 /* First expand the arguments. */
9361 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9362 setstackmark(&smark);
9363 back_exitstatus = 0;
9364
9365 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009366 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009367 varlist.lastp = &varlist.list;
9368 *varlist.lastp = NULL;
9369 arglist.lastp = &arglist.list;
9370 *arglist.lastp = NULL;
9371
9372 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009373 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009374 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9375 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9376 }
9377
Eric Andersenc470f442003-07-28 09:56:35 +00009378 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9379 struct strlist **spp;
9380
9381 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009382 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009383 expandarg(argp, &arglist, EXP_VARTILDE);
9384 else
9385 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9386
Eric Andersenc470f442003-07-28 09:56:35 +00009387 for (sp = *spp; sp; sp = sp->next)
9388 argc++;
9389 }
9390
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009391 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009392 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009393 TRACE(("evalcommand arg: %s\n", sp->text));
9394 *nargv++ = sp->text;
9395 }
9396 *nargv = NULL;
9397
9398 lastarg = NULL;
9399 if (iflag && funcnest == 0 && argc > 0)
9400 lastarg = nargv[-1];
9401
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009402 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009403 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009404 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009405
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009406 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009407 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9408 struct strlist **spp;
9409 char *p;
9410
9411 spp = varlist.lastp;
9412 expandarg(argp, &varlist, EXP_VARTILDE);
9413
9414 /*
9415 * Modify the command lookup path, if a PATH= assignment
9416 * is present
9417 */
9418 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009419 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009420 path = p;
9421 }
9422
9423 /* Print the command if xflag is set. */
9424 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009425 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009426 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009427
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009428 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009429 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009430 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009431 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009432 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009433 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009434 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009435 }
9436 sp = arglist.list;
9437 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009438 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009439 }
9440
9441 cmd_is_exec = 0;
9442 spclbltin = -1;
9443
9444 /* Now locate the command. */
9445 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009446 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009447#if ENABLE_ASH_CMDCMD
9448 const char *oldpath = path + 5;
9449#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009450 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009451 for (;;) {
9452 find_command(argv[0], &cmdentry, cmd_flag, path);
9453 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009454 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009455 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009456 goto bail;
9457 }
9458
9459 /* implement bltin and command here */
9460 if (cmdentry.cmdtype != CMDBUILTIN)
9461 break;
9462 if (spclbltin < 0)
9463 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9464 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009465 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009466#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009467 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009468 path = oldpath;
9469 nargv = parse_command_args(argv, &path);
9470 if (!nargv)
9471 break;
9472 argc -= nargv - argv;
9473 argv = nargv;
9474 cmd_flag |= DO_NOFUNC;
9475 } else
9476#endif
9477 break;
9478 }
9479 }
9480
9481 if (status) {
9482 /* We have a redirection error. */
9483 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009484 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009485 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009486 exitstatus = status;
9487 goto out;
9488 }
9489
9490 /* Execute the command. */
9491 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009492 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009493
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009494#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009495/* (1) BUG: if variables are set, we need to fork, or save/restore them
9496 * around run_nofork_applet() call.
9497 * (2) Should this check also be done in forkshell()?
9498 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9499 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009500 /* find_command() encodes applet_no as (-2 - applet_no) */
9501 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009502 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009503 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009504 /* run <applet>_main() */
9505 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009506 break;
9507 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009508#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009509 /* Can we avoid forking off? For example, very last command
9510 * in a script or a subshell does not need forking,
9511 * we can just exec it.
9512 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009513 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009514 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009515 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009516 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009517 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009518 /* parent */
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009519 status = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009520 INT_ON;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009521 TRACE(("forked child exited with %d\n", status));
Eric Andersenc470f442003-07-28 09:56:35 +00009522 break;
9523 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009524 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009525 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009526 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009527 }
9528 listsetvar(varlist.list, VEXPORT|VSTACK);
9529 shellexec(argv, path, cmdentry.u.index);
9530 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009531 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009532 case CMDBUILTIN:
9533 cmdenviron = varlist.list;
9534 if (cmdenviron) {
9535 struct strlist *list = cmdenviron;
9536 int i = VNOSET;
9537 if (spclbltin > 0 || argc == 0) {
9538 i = 0;
9539 if (cmd_is_exec && argc > 1)
9540 i = VEXPORT;
9541 }
9542 listsetvar(list, i);
9543 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009544 /* Tight loop with builtins only:
9545 * "while kill -0 $child; do true; done"
9546 * will never exit even if $child died, unless we do this
9547 * to reap the zombie and make kill detect that it's gone: */
9548 dowait(DOWAIT_NONBLOCK, NULL);
9549
Eric Andersenc470f442003-07-28 09:56:35 +00009550 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9551 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009552 int i = exception_type;
Ron Yorston8c55dc72015-10-30 19:06:47 +00009553 if (i == EXEXIT || i == EXEXEC)
Eric Andersenc470f442003-07-28 09:56:35 +00009554 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009555 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009556 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009557 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009558 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009559 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009560 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009561 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009562 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009563 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009564 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009565 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009566 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009567 goto readstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009568
9569 case CMDFUNCTION:
9570 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009571 /* See above for the rationale */
9572 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009573 if (evalfun(cmdentry.u.func, argc, argv, flags))
9574 goto raise;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009575 readstatus:
9576 status = exitstatus;
Eric Andersenc470f442003-07-28 09:56:35 +00009577 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009578 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009579
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009580 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009581 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009582 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009583 /* dsl: I think this is intended to be used to support
9584 * '_' in 'vi' command mode during line editing...
9585 * However I implemented that within libedit itself.
9586 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009587 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009588 }
Eric Andersenc470f442003-07-28 09:56:35 +00009589 popstackmark(&smark);
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +02009590
9591 return status;
Eric Andersenc470f442003-07-28 09:56:35 +00009592}
9593
9594static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009595evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9596{
Eric Andersenc470f442003-07-28 09:56:35 +00009597 char *volatile savecmdname;
9598 struct jmploc *volatile savehandler;
9599 struct jmploc jmploc;
9600 int i;
9601
9602 savecmdname = commandname;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009603 i = setjmp(jmploc.loc);
9604 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009605 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009606 savehandler = exception_handler;
9607 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009608 commandname = argv[0];
9609 argptr = argv + 1;
9610 optptr = NULL; /* initialize nextopt */
9611 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009612 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009613 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009614 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009615 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009616 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009617 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009618
9619 return i;
9620}
9621
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009622static int
9623goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009624{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009625 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009626}
9627
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009628
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009629/*
9630 * Search for a command. This is called before we fork so that the
9631 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009632 * the child. The check for "goodname" is an overly conservative
9633 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009634 */
Eric Andersenc470f442003-07-28 09:56:35 +00009635static void
9636prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009637{
9638 struct cmdentry entry;
9639
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009640 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9641 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009642}
9643
Eric Andersencb57d552001-06-28 07:25:16 +00009644
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009645/* ============ Builtin commands
9646 *
9647 * Builtin commands whose functions are closely tied to evaluation
9648 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009649 */
9650
9651/*
Eric Andersencb57d552001-06-28 07:25:16 +00009652 * Handle break and continue commands. Break, continue, and return are
9653 * all handled by setting the evalskip flag. The evaluation routines
9654 * above all check this flag, and if it is set they start skipping
9655 * commands rather than executing them. The variable skipcount is
9656 * the number of loops to break/continue, or the number of function
9657 * levels to return. (The latter is always 1.) It should probably
9658 * be an error to break out of more loops than exist, but it isn't
9659 * in the standard shell so we don't make it one here.
9660 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009661static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009662breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009663{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009664 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009665
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009666 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009667 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009668 if (n > loopnest)
9669 n = loopnest;
9670 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009671 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009672 skipcount = n;
9673 }
9674 return 0;
9675}
9676
Eric Andersenc470f442003-07-28 09:56:35 +00009677
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009678/* ============ input.c
9679 *
Eric Andersen90898442003-08-06 11:20:52 +00009680 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009681 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009682
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009683enum {
9684 INPUT_PUSH_FILE = 1,
9685 INPUT_NOFILE_OK = 2,
9686};
Eric Andersencb57d552001-06-28 07:25:16 +00009687
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009688static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009689/* values of checkkwd variable */
9690#define CHKALIAS 0x1
9691#define CHKKWD 0x2
9692#define CHKNL 0x4
9693
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009694/*
9695 * Push a string back onto the input at this current parsefile level.
9696 * We handle aliases this way.
9697 */
9698#if !ENABLE_ASH_ALIAS
9699#define pushstring(s, ap) pushstring(s)
9700#endif
9701static void
9702pushstring(char *s, struct alias *ap)
9703{
9704 struct strpush *sp;
9705 int len;
9706
9707 len = strlen(s);
9708 INT_OFF;
9709 if (g_parsefile->strpush) {
9710 sp = ckzalloc(sizeof(*sp));
9711 sp->prev = g_parsefile->strpush;
9712 } else {
9713 sp = &(g_parsefile->basestrpush);
9714 }
9715 g_parsefile->strpush = sp;
9716 sp->prev_string = g_parsefile->next_to_pgetc;
9717 sp->prev_left_in_line = g_parsefile->left_in_line;
9718#if ENABLE_ASH_ALIAS
9719 sp->ap = ap;
9720 if (ap) {
9721 ap->flag |= ALIASINUSE;
9722 sp->string = s;
9723 }
9724#endif
9725 g_parsefile->next_to_pgetc = s;
9726 g_parsefile->left_in_line = len;
9727 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;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009754 g_parsefile->strpush = sp->prev;
9755 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009756 free(sp);
9757 INT_ON;
9758}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009759
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009760//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9761//it peeks whether it is &>, and then pushes back both chars.
9762//This function needs to save last *next_to_pgetc to buf[0]
9763//to make two pungetc() reliable. Currently,
9764// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009765static int
9766preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009767{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009768 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009769 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009770
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009771 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009772#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009773 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009774 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009775 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009776 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009777 int timeout = -1;
9778# if ENABLE_ASH_IDLE_TIMEOUT
9779 if (iflag) {
9780 const char *tmout_var = lookupvar("TMOUT");
9781 if (tmout_var) {
9782 timeout = atoi(tmout_var) * 1000;
9783 if (timeout <= 0)
9784 timeout = -1;
9785 }
9786 }
9787# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009788# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009789 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009790# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009791 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009792 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009793 if (nr == 0) {
9794 /* Ctrl+C pressed */
9795 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009796 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009797 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009798 raise(SIGINT);
9799 return 1;
9800 }
Eric Andersenc470f442003-07-28 09:56:35 +00009801 goto retry;
9802 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009803 if (nr < 0) {
9804 if (errno == 0) {
9805 /* Ctrl+D pressed */
9806 nr = 0;
9807 }
9808# if ENABLE_ASH_IDLE_TIMEOUT
9809 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009810 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009811 exitshell();
9812 }
9813# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009814 }
Eric Andersencb57d552001-06-28 07:25:16 +00009815 }
9816#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009817 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009818#endif
9819
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009820#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009821 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009822 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009823 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009824 if (flags >= 0 && (flags & O_NONBLOCK)) {
9825 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009826 if (fcntl(0, F_SETFL, flags) >= 0) {
9827 out2str("sh: turning off NDELAY mode\n");
9828 goto retry;
9829 }
9830 }
9831 }
9832 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009833#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009834 return nr;
9835}
9836
9837/*
9838 * Refill the input buffer and return the next input character:
9839 *
9840 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009841 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9842 * or we are reading from a string so we can't refill the buffer,
9843 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009844 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009845 * 4) Process input up to the next newline, deleting nul characters.
9846 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009847//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9848#define pgetc_debug(...) ((void)0)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009849static int
Eric Andersenc470f442003-07-28 09:56:35 +00009850preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009851{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009852 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009853 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009854
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009855 while (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009856#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009857 if (g_parsefile->left_in_line == -1
9858 && g_parsefile->strpush->ap
9859 && g_parsefile->next_to_pgetc[-1] != ' '
9860 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009861 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009862 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009863 return PEOA;
9864 }
Eric Andersen2870d962001-07-02 17:27:21 +00009865#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009866 popstring();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009867 /* try "pgetc" now: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009868 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9869 g_parsefile->left_in_line,
9870 g_parsefile->next_to_pgetc,
9871 g_parsefile->next_to_pgetc);
9872 if (--g_parsefile->left_in_line >= 0)
9873 return (unsigned char)(*g_parsefile->next_to_pgetc++);
Eric Andersencb57d552001-06-28 07:25:16 +00009874 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009875 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009876 * "pgetc" needs refilling.
9877 */
9878
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009879 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009880 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009881 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009882 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009883 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009884 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009885 /* even in failure keep left_in_line and next_to_pgetc
9886 * in lock step, for correct multi-layer pungetc.
9887 * left_in_line was decremented before preadbuffer(),
9888 * must inc next_to_pgetc: */
9889 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009890 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009891 }
Eric Andersencb57d552001-06-28 07:25:16 +00009892
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009893 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009894 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009895 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009896 again:
9897 more = preadfd();
9898 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009899 /* don't try reading again */
9900 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009901 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009902 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009903 return PEOF;
9904 }
9905 }
9906
Denis Vlasenko727752d2008-11-28 03:41:47 +00009907 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009908 * Set g_parsefile->left_in_line
9909 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009910 * NUL chars are deleted.
9911 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009912 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009913 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009914 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009915
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009916 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009917
Denis Vlasenko727752d2008-11-28 03:41:47 +00009918 c = *q;
9919 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009920 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009921 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009922 q++;
9923 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009924 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009925 break;
9926 }
Eric Andersencb57d552001-06-28 07:25:16 +00009927 }
9928
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009929 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009930 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9931 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009932 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009933 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009934 }
9935 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009936 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009937
Eric Andersencb57d552001-06-28 07:25:16 +00009938 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009939 char save = *q;
9940 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009941 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009942 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009943 }
9944
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009945 pgetc_debug("preadbuffer at %d:%p'%s'",
9946 g_parsefile->left_in_line,
9947 g_parsefile->next_to_pgetc,
9948 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009949 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009950}
9951
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009952#define pgetc_as_macro() \
9953 (--g_parsefile->left_in_line >= 0 \
Denys Vlasenkocd716832009-11-28 22:14:02 +01009954 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009955 : preadbuffer() \
9956 )
Denis Vlasenko727752d2008-11-28 03:41:47 +00009957
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009958static int
9959pgetc(void)
9960{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009961 pgetc_debug("pgetc_fast at %d:%p'%s'",
9962 g_parsefile->left_in_line,
9963 g_parsefile->next_to_pgetc,
9964 g_parsefile->next_to_pgetc);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009965 return pgetc_as_macro();
9966}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009967
9968#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009969# define pgetc_fast() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009970#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009971# define pgetc_fast() pgetc_as_macro()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009972#endif
9973
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009974#if ENABLE_ASH_ALIAS
9975static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009976pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009977{
9978 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009979 do {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009980 pgetc_debug("pgetc_fast at %d:%p'%s'",
9981 g_parsefile->left_in_line,
9982 g_parsefile->next_to_pgetc,
9983 g_parsefile->next_to_pgetc);
Denis Vlasenko834dee72008-10-07 09:18:30 +00009984 c = pgetc_fast();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009985 } while (c == PEOA);
9986 return c;
9987}
9988#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009989# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009990#endif
9991
9992/*
9993 * Read a line from the script.
9994 */
9995static char *
9996pfgets(char *line, int len)
9997{
9998 char *p = line;
9999 int nleft = len;
10000 int c;
10001
10002 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010010003 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010004 if (c == PEOF) {
10005 if (p == line)
10006 return NULL;
10007 break;
10008 }
10009 *p++ = c;
10010 if (c == '\n')
10011 break;
10012 }
10013 *p = '\0';
10014 return line;
10015}
10016
Eric Andersenc470f442003-07-28 09:56:35 +000010017/*
10018 * Undo the last call to pgetc. Only one character may be pushed back.
10019 * PEOF may be pushed back.
10020 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010021static void
Eric Andersenc470f442003-07-28 09:56:35 +000010022pungetc(void)
10023{
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010024 g_parsefile->left_in_line++;
10025 g_parsefile->next_to_pgetc--;
10026 pgetc_debug("pushed back to %d:%p'%s'",
10027 g_parsefile->left_in_line,
10028 g_parsefile->next_to_pgetc,
10029 g_parsefile->next_to_pgetc);
Eric Andersencb57d552001-06-28 07:25:16 +000010030}
10031
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010032/*
10033 * To handle the "." command, a stack of input files is used. Pushfile
10034 * adds a new entry to the stack and popfile restores the previous level.
10035 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010036static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010037pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +000010038{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010039 struct parsefile *pf;
10040
Denis Vlasenko597906c2008-02-20 16:38:54 +000010041 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010042 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010043 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010044 /*pf->strpush = NULL; - ckzalloc did it */
10045 /*pf->basestrpush.prev = NULL;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010046 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010047}
10048
10049static void
10050popfile(void)
10051{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010052 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +000010053
Denis Vlasenkob012b102007-02-19 22:43:01 +000010054 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010055 if (pf->pf_fd >= 0)
10056 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +000010057 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010058 while (pf->strpush)
10059 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010060 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010061 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +000010062 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000010063}
10064
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010065/*
10066 * Return to top level.
10067 */
10068static void
10069popallfiles(void)
10070{
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010071 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010072 popfile();
10073}
10074
10075/*
10076 * Close the file(s) that the shell is reading commands from. Called
10077 * after a fork is done.
10078 */
10079static void
10080closescript(void)
10081{
10082 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010083 if (g_parsefile->pf_fd > 0) {
10084 close(g_parsefile->pf_fd);
10085 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010086 }
10087}
10088
10089/*
10090 * Like setinputfile, but takes an open file descriptor. Call this with
10091 * interrupts off.
10092 */
10093static void
10094setinputfd(int fd, int push)
10095{
Denis Vlasenko96e1b382007-09-30 23:50:48 +000010096 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010097 if (push) {
10098 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010099 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010100 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010101 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010102 if (g_parsefile->buf == NULL)
10103 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010104 g_parsefile->left_in_buffer = 0;
10105 g_parsefile->left_in_line = 0;
10106 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010107}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010108
Eric Andersenc470f442003-07-28 09:56:35 +000010109/*
10110 * Set the input to take input from a file. If push is set, push the
10111 * old input onto the stack first.
10112 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010113static int
10114setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010115{
10116 int fd;
10117 int fd2;
10118
Denis Vlasenkob012b102007-02-19 22:43:01 +000010119 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010120 fd = open(fname, O_RDONLY);
10121 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010122 if (flags & INPUT_NOFILE_OK)
10123 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010124 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010125 }
Eric Andersenc470f442003-07-28 09:56:35 +000010126 if (fd < 10) {
10127 fd2 = copyfd(fd, 10);
10128 close(fd);
10129 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010130 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010131 fd = fd2;
10132 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010133 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010134 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010135 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010136 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010137}
10138
Eric Andersencb57d552001-06-28 07:25:16 +000010139/*
10140 * Like setinputfile, but takes input from a string.
10141 */
Eric Andersenc470f442003-07-28 09:56:35 +000010142static void
10143setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010144{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010145 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010146 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010147 g_parsefile->next_to_pgetc = string;
10148 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010149 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010150 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010151 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010152}
10153
10154
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010155/* ============ mail.c
10156 *
10157 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010158 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010159
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010160#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010161
Denys Vlasenko23841622015-10-09 15:52:03 +020010162/* Hash of mtimes of mailboxes */
10163static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010164/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010165static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010166
Eric Andersencb57d552001-06-28 07:25:16 +000010167/*
Eric Andersenc470f442003-07-28 09:56:35 +000010168 * Print appropriate message(s) if mail has arrived.
10169 * If mail_var_path_changed is set,
10170 * then the value of MAIL has mail_var_path_changed,
10171 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010172 */
Eric Andersenc470f442003-07-28 09:56:35 +000010173static void
10174chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010175{
Eric Andersencb57d552001-06-28 07:25:16 +000010176 const char *mpath;
10177 char *p;
10178 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010179 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010180 struct stackmark smark;
10181 struct stat statb;
10182
Eric Andersencb57d552001-06-28 07:25:16 +000010183 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010184 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010185 new_hash = 0;
10186 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010187 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010188 if (p == NULL)
10189 break;
10190 if (*p == '\0')
10191 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010192 for (q = p; *q; q++)
10193 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010194#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010195 if (q[-1] != '/')
10196 abort();
10197#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010198 q[-1] = '\0'; /* delete trailing '/' */
10199 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010200 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010201 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010202 /* Very simplistic "hash": just a sum of all mtimes */
10203 new_hash += (unsigned)statb.st_mtime;
10204 }
10205 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010206 if (mailtime_hash != 0)
10207 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010208 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010209 }
Eric Andersenc470f442003-07-28 09:56:35 +000010210 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010211 popstackmark(&smark);
10212}
Eric Andersencb57d552001-06-28 07:25:16 +000010213
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010214static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010215changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010216{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010217 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010218}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010219
Denis Vlasenko131ae172007-02-18 13:00:19 +000010220#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010221
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010222
10223/* ============ ??? */
10224
Eric Andersencb57d552001-06-28 07:25:16 +000010225/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010226 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010227 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010228static void
10229setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010230{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010231 char **newparam;
10232 char **ap;
10233 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010234
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010235 for (nparam = 0; argv[nparam]; nparam++)
10236 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010237 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10238 while (*argv) {
10239 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010240 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010241 *ap = NULL;
10242 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010243 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010244 shellparam.nparam = nparam;
10245 shellparam.p = newparam;
10246#if ENABLE_ASH_GETOPTS
10247 shellparam.optind = 1;
10248 shellparam.optoff = -1;
10249#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010250}
10251
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010252/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010253 * Process shell options. The global variable argptr contains a pointer
10254 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010255 *
10256 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10257 * For a non-interactive shell, an error condition encountered
10258 * by a special built-in ... shall cause the shell to write a diagnostic message
10259 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010260 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010261 * ...
10262 * Utility syntax error (option or operand error) Shall exit
10263 * ...
10264 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10265 * we see that bash does not do that (set "finishes" with error code 1 instead,
10266 * and shell continues), and people rely on this behavior!
10267 * Testcase:
10268 * set -o barfoo 2>/dev/null
10269 * echo $?
10270 *
10271 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010272 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010273static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010274plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010275{
10276 int i;
10277
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010278 if (name) {
10279 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010280 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010281 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010282 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010283 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010284 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010285 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010286 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010287 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010288 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010289 if (val) {
10290 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10291 } else {
10292 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10293 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010294 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010295 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010296}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010297static void
10298setoption(int flag, int val)
10299{
10300 int i;
10301
10302 for (i = 0; i < NOPTS; i++) {
10303 if (optletters(i) == flag) {
10304 optlist[i] = val;
10305 return;
10306 }
10307 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010308 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010309 /* NOTREACHED */
10310}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010311static int
Eric Andersenc470f442003-07-28 09:56:35 +000010312options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010313{
10314 char *p;
10315 int val;
10316 int c;
10317
10318 if (cmdline)
10319 minusc = NULL;
10320 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010321 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010322 if (c != '-' && c != '+')
10323 break;
10324 argptr++;
10325 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010326 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010327 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010328 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010329 if (!cmdline) {
10330 /* "-" means turn off -x and -v */
10331 if (p[0] == '\0')
10332 xflag = vflag = 0;
10333 /* "--" means reset params */
10334 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010335 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010336 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010337 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010338 }
Eric Andersencb57d552001-06-28 07:25:16 +000010339 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010340 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010341 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010342 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010343 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010344 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010345 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010346 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010347 /* it already printed err message */
10348 return 1; /* error */
10349 }
Eric Andersencb57d552001-06-28 07:25:16 +000010350 if (*argptr)
10351 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010352 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10353 isloginsh = 1;
10354 /* bash does not accept +-login, we also won't */
10355 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010356 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010357 isloginsh = 1;
10358 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010359 } else {
10360 setoption(c, val);
10361 }
10362 }
10363 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010364 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010365}
10366
Eric Andersencb57d552001-06-28 07:25:16 +000010367/*
Eric Andersencb57d552001-06-28 07:25:16 +000010368 * The shift builtin command.
10369 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010370static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010371shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010372{
10373 int n;
10374 char **ap1, **ap2;
10375
10376 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010377 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010378 n = number(argv[1]);
10379 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010380 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010381 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010382 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010383 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010384 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010385 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010386 }
10387 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010388 while ((*ap2++ = *ap1++) != NULL)
10389 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010390#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010391 shellparam.optind = 1;
10392 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010393#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010394 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010395 return 0;
10396}
10397
Eric Andersencb57d552001-06-28 07:25:16 +000010398/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010399 * POSIX requires that 'set' (but not export or readonly) output the
10400 * variables in lexicographic order - by the locale's collating order (sigh).
10401 * Maybe we could keep them in an ordered balanced binary tree
10402 * instead of hashed lists.
10403 * For now just roll 'em through qsort for printing...
10404 */
10405static int
10406showvars(const char *sep_prefix, int on, int off)
10407{
10408 const char *sep;
10409 char **ep, **epend;
10410
10411 ep = listvars(on, off, &epend);
10412 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10413
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010414 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010415
10416 for (; ep < epend; ep++) {
10417 const char *p;
10418 const char *q;
10419
10420 p = strchrnul(*ep, '=');
10421 q = nullstr;
10422 if (*p)
10423 q = single_quote(++p);
10424 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10425 }
10426 return 0;
10427}
10428
10429/*
Eric Andersencb57d552001-06-28 07:25:16 +000010430 * The set command builtin.
10431 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010432static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010433setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010434{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010435 int retval;
10436
Denis Vlasenko68404f12008-03-17 09:00:54 +000010437 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010438 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010439
Denis Vlasenkob012b102007-02-19 22:43:01 +000010440 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010441 retval = options(/*cmdline:*/ 0);
10442 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010443 optschanged();
10444 if (*argptr != NULL) {
10445 setparam(argptr);
10446 }
Eric Andersencb57d552001-06-28 07:25:16 +000010447 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010448 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010449 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010450}
10451
Denis Vlasenko131ae172007-02-18 13:00:19 +000010452#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010453static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010454change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010455{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010456 uint32_t t;
10457
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010458 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010459 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010460 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010461 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010462 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010463 vrandom.flags &= ~VNOFUNC;
10464 } else {
10465 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010466 t = strtoul(value, NULL, 10);
10467 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010468 }
Eric Andersenef02f822004-03-11 13:34:24 +000010469}
Eric Andersen16767e22004-03-16 05:14:10 +000010470#endif
10471
Denis Vlasenko131ae172007-02-18 13:00:19 +000010472#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010473static int
Eric Andersenc470f442003-07-28 09:56:35 +000010474getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010475{
10476 char *p, *q;
10477 char c = '?';
10478 int done = 0;
10479 int err = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010480 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010481 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010482
Denys Vlasenko9c541002015-10-07 15:44:36 +020010483 sbuf[1] = '\0';
10484
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010485 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010486 return 1;
10487 optnext = optfirst + *param_optind - 1;
10488
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010489 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010490 p = NULL;
10491 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010492 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010493 if (p == NULL || *p == '\0') {
10494 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010495 p = *optnext;
10496 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010497 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010498 p = NULL;
10499 done = 1;
10500 goto out;
10501 }
10502 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010503 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010504 goto atend;
10505 }
10506
10507 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010508 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010509 if (*q == '\0') {
10510 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010511 sbuf[0] = c;
10512 /*sbuf[1] = '\0'; - already is */
10513 err |= setvarsafe("OPTARG", sbuf, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010514 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010515 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010516 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010517 }
10518 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010519 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010520 }
10521 if (*++q == ':')
10522 q++;
10523 }
10524
10525 if (*++q == ':') {
10526 if (*p == '\0' && (p = *optnext) == NULL) {
10527 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010528 sbuf[0] = c;
10529 /*sbuf[1] = '\0'; - already is */
10530 err |= setvarsafe("OPTARG", sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010531 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010532 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010533 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010534 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010535 c = '?';
10536 }
Eric Andersenc470f442003-07-28 09:56:35 +000010537 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010538 }
10539
10540 if (p == *optnext)
10541 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010542 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010543 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010544 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010545 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010546 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010547 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010548 *param_optind = optnext - optfirst + 1;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010549 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC);
10550 sbuf[0] = c;
10551 /*sbuf[1] = '\0'; - already is */
10552 err |= setvarsafe(optvar, sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010553 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010554 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010555 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010556 flush_stdout_stderr();
10557 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010558 }
10559 return done;
10560}
Eric Andersenc470f442003-07-28 09:56:35 +000010561
10562/*
10563 * The getopts builtin. Shellparam.optnext points to the next argument
10564 * to be processed. Shellparam.optptr points to the next character to
10565 * be processed in the current argument. If shellparam.optnext is NULL,
10566 * then it's the first time getopts has been called.
10567 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010568static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010569getoptscmd(int argc, char **argv)
10570{
10571 char **optbase;
10572
10573 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010574 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010575 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010576 optbase = shellparam.p;
10577 if (shellparam.optind > shellparam.nparam + 1) {
10578 shellparam.optind = 1;
10579 shellparam.optoff = -1;
10580 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010581 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010582 optbase = &argv[3];
10583 if (shellparam.optind > argc - 2) {
10584 shellparam.optind = 1;
10585 shellparam.optoff = -1;
10586 }
10587 }
10588
10589 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010590 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010591}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010592#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010593
Eric Andersencb57d552001-06-28 07:25:16 +000010594
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010595/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010596
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010597struct heredoc {
10598 struct heredoc *next; /* next here document in list */
10599 union node *here; /* redirection node */
10600 char *eofmark; /* string indicating end of input */
10601 smallint striptabs; /* if set, strip leading tabs */
10602};
10603
10604static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010605static smallint quoteflag; /* set if (part of) last token was quoted */
10606static token_id_t lasttoken; /* last token read (integer id Txxx) */
10607static struct heredoc *heredoclist; /* list of here documents to read */
10608static char *wordtext; /* text of last word returned by readtoken */
10609static struct nodelist *backquotelist;
10610static union node *redirnode;
10611static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010612
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010613static const char *
10614tokname(char *buf, int tok)
10615{
10616 if (tok < TSEMI)
10617 return tokname_array[tok] + 1;
10618 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10619 return buf;
10620}
10621
10622/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010623 * Called when an unexpected token is read during the parse. The argument
10624 * is the token that is expected, or -1 if more than one type of token can
10625 * occur at this point.
10626 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010627static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010628static void
10629raise_error_unexpected_syntax(int token)
10630{
10631 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010632 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010633 int l;
10634
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010635 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010636 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010637 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010638 raise_error_syntax(msg);
10639 /* NOTREACHED */
10640}
Eric Andersencb57d552001-06-28 07:25:16 +000010641
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010642#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010643
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010644/* parsing is heavily cross-recursive, need these forward decls */
10645static union node *andor(void);
10646static union node *pipeline(void);
10647static union node *parse_command(void);
10648static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010649static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010650static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010651
Eric Andersenc470f442003-07-28 09:56:35 +000010652static union node *
10653list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010654{
10655 union node *n1, *n2, *n3;
10656 int tok;
10657
Eric Andersencb57d552001-06-28 07:25:16 +000010658 n1 = NULL;
10659 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010660 switch (peektoken()) {
10661 case TNL:
10662 if (!(nlflag & 1))
10663 break;
10664 parseheredoc();
10665 return n1;
10666
10667 case TEOF:
10668 if (!n1 && (nlflag & 1))
10669 n1 = NODE_EOF;
10670 parseheredoc();
10671 return n1;
10672 }
10673
10674 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10675 if (nlflag == 2 && tokname_array[peektoken()][0])
10676 return n1;
10677 nlflag |= 2;
10678
Eric Andersencb57d552001-06-28 07:25:16 +000010679 n2 = andor();
10680 tok = readtoken();
10681 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010682 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010683 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010684 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010685 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010686 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010687 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010688 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010689 n2 = n3;
10690 }
10691 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010692 }
10693 }
10694 if (n1 == NULL) {
10695 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010696 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010697 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010698 n3->type = NSEMI;
10699 n3->nbinary.ch1 = n1;
10700 n3->nbinary.ch2 = n2;
10701 n1 = n3;
10702 }
10703 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010704 case TNL:
10705 case TEOF:
10706 tokpushback = 1;
10707 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010708 case TBACKGND:
10709 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010710 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010711 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010712 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010713 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010714 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010715 return n1;
10716 }
10717 }
10718}
10719
Eric Andersenc470f442003-07-28 09:56:35 +000010720static union node *
10721andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010722{
Eric Andersencb57d552001-06-28 07:25:16 +000010723 union node *n1, *n2, *n3;
10724 int t;
10725
Eric Andersencb57d552001-06-28 07:25:16 +000010726 n1 = pipeline();
10727 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010728 t = readtoken();
10729 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010730 t = NAND;
10731 } else if (t == TOR) {
10732 t = NOR;
10733 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010734 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010735 return n1;
10736 }
Eric Andersenc470f442003-07-28 09:56:35 +000010737 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010738 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010739 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010740 n3->type = t;
10741 n3->nbinary.ch1 = n1;
10742 n3->nbinary.ch2 = n2;
10743 n1 = n3;
10744 }
10745}
10746
Eric Andersenc470f442003-07-28 09:56:35 +000010747static union node *
10748pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010749{
Eric Andersencb57d552001-06-28 07:25:16 +000010750 union node *n1, *n2, *pipenode;
10751 struct nodelist *lp, *prev;
10752 int negate;
10753
10754 negate = 0;
10755 TRACE(("pipeline: entered\n"));
10756 if (readtoken() == TNOT) {
10757 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010758 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010759 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010760 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010761 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010762 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010763 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010764 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010765 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010766 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010767 pipenode->npipe.cmdlist = lp;
10768 lp->n = n1;
10769 do {
10770 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010771 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010772 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010773 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010774 prev->next = lp;
10775 } while (readtoken() == TPIPE);
10776 lp->next = NULL;
10777 n1 = pipenode;
10778 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010779 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010780 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010781 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010782 n2->type = NNOT;
10783 n2->nnot.com = n1;
10784 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010785 }
10786 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010787}
10788
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010789static union node *
10790makename(void)
10791{
10792 union node *n;
10793
Denis Vlasenko597906c2008-02-20 16:38:54 +000010794 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010795 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010796 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010797 n->narg.text = wordtext;
10798 n->narg.backquote = backquotelist;
10799 return n;
10800}
10801
10802static void
10803fixredir(union node *n, const char *text, int err)
10804{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010805 int fd;
10806
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010807 TRACE(("Fix redir %s %d\n", text, err));
10808 if (!err)
10809 n->ndup.vname = NULL;
10810
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010811 fd = bb_strtou(text, NULL, 10);
10812 if (!errno && fd >= 0)
10813 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010814 else if (LONE_DASH(text))
10815 n->ndup.dupfd = -1;
10816 else {
10817 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010818 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010819 n->ndup.vname = makename();
10820 }
10821}
10822
10823/*
10824 * Returns true if the text contains nothing to expand (no dollar signs
10825 * or backquotes).
10826 */
10827static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010828noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010829{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010830 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010831
Denys Vlasenkocd716832009-11-28 22:14:02 +010010832 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010833 if (c == CTLQUOTEMARK)
10834 continue;
10835 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010836 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010837 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010838 return 0;
10839 }
10840 return 1;
10841}
10842
10843static void
10844parsefname(void)
10845{
10846 union node *n = redirnode;
10847
10848 if (readtoken() != TWORD)
10849 raise_error_unexpected_syntax(-1);
10850 if (n->type == NHERE) {
10851 struct heredoc *here = heredoc;
10852 struct heredoc *p;
10853 int i;
10854
10855 if (quoteflag == 0)
10856 n->type = NXHERE;
10857 TRACE(("Here document %d\n", n->type));
10858 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010859 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010860 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010861 here->eofmark = wordtext;
10862 here->next = NULL;
10863 if (heredoclist == NULL)
10864 heredoclist = here;
10865 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010866 for (p = heredoclist; p->next; p = p->next)
10867 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010868 p->next = here;
10869 }
10870 } else if (n->type == NTOFD || n->type == NFROMFD) {
10871 fixredir(n, wordtext, 0);
10872 } else {
10873 n->nfile.fname = makename();
10874 }
10875}
Eric Andersencb57d552001-06-28 07:25:16 +000010876
Eric Andersenc470f442003-07-28 09:56:35 +000010877static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010878simplecmd(void)
10879{
10880 union node *args, **app;
10881 union node *n = NULL;
10882 union node *vars, **vpp;
10883 union node **rpp, *redir;
10884 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010885#if ENABLE_ASH_BASH_COMPAT
10886 smallint double_brackets_flag = 0;
Ron Yorston95ebcf72015-11-03 09:42:23 +000010887 smallint function_flag = 0;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010888#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010889
10890 args = NULL;
10891 app = &args;
10892 vars = NULL;
10893 vpp = &vars;
10894 redir = NULL;
10895 rpp = &redir;
10896
10897 savecheckkwd = CHKALIAS;
10898 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010899 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010900 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010901 t = readtoken();
10902 switch (t) {
10903#if ENABLE_ASH_BASH_COMPAT
Ron Yorston95ebcf72015-11-03 09:42:23 +000010904 case TFUNCTION:
10905 if (peektoken() != TWORD)
10906 raise_error_unexpected_syntax(TWORD);
10907 function_flag = 1;
10908 break;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010909 case TAND: /* "&&" */
10910 case TOR: /* "||" */
10911 if (!double_brackets_flag) {
10912 tokpushback = 1;
10913 goto out;
10914 }
10915 wordtext = (char *) (t == TAND ? "-a" : "-o");
10916#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010917 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010918 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010919 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010920 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010921 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010922#if ENABLE_ASH_BASH_COMPAT
10923 if (strcmp("[[", wordtext) == 0)
10924 double_brackets_flag = 1;
10925 else if (strcmp("]]", wordtext) == 0)
10926 double_brackets_flag = 0;
10927#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010928 n->narg.backquote = backquotelist;
10929 if (savecheckkwd && isassignment(wordtext)) {
10930 *vpp = n;
10931 vpp = &n->narg.next;
10932 } else {
10933 *app = n;
10934 app = &n->narg.next;
10935 savecheckkwd = 0;
10936 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000010937#if ENABLE_ASH_BASH_COMPAT
10938 if (function_flag) {
10939 checkkwd = CHKNL | CHKKWD;
10940 switch (peektoken()) {
10941 case TBEGIN:
10942 case TIF:
10943 case TCASE:
10944 case TUNTIL:
10945 case TWHILE:
10946 case TFOR:
10947 goto do_func;
10948 case TLP:
10949 function_flag = 0;
10950 break;
10951 case TWORD:
10952 if (strcmp("[[", wordtext) == 0)
10953 goto do_func;
10954 /* fall through */
10955 default:
10956 raise_error_unexpected_syntax(-1);
10957 }
10958 }
10959#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010960 break;
10961 case TREDIR:
10962 *rpp = n = redirnode;
10963 rpp = &n->nfile.next;
10964 parsefname(); /* read name of redirection file */
10965 break;
10966 case TLP:
Ron Yorston95ebcf72015-11-03 09:42:23 +000010967 IF_ASH_BASH_COMPAT(do_func:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010968 if (args && app == &args->narg.next
10969 && !vars && !redir
10970 ) {
10971 struct builtincmd *bcmd;
10972 const char *name;
10973
10974 /* We have a function */
Ron Yorston95ebcf72015-11-03 09:42:23 +000010975 if (IF_ASH_BASH_COMPAT(!function_flag &&) readtoken() != TRP)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010976 raise_error_unexpected_syntax(TRP);
10977 name = n->narg.text;
10978 if (!goodname(name)
10979 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10980 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010981 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010982 }
10983 n->type = NDEFUN;
10984 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10985 n->narg.next = parse_command();
10986 return n;
10987 }
Ron Yorston95ebcf72015-11-03 09:42:23 +000010988 IF_ASH_BASH_COMPAT(function_flag = 0;)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010989 /* fall through */
10990 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010991 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010992 goto out;
10993 }
10994 }
10995 out:
10996 *app = NULL;
10997 *vpp = NULL;
10998 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010999 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011000 n->type = NCMD;
11001 n->ncmd.args = args;
11002 n->ncmd.assign = vars;
11003 n->ncmd.redirect = redir;
11004 return n;
11005}
11006
11007static union node *
11008parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011009{
Eric Andersencb57d552001-06-28 07:25:16 +000011010 union node *n1, *n2;
11011 union node *ap, **app;
11012 union node *cp, **cpp;
11013 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011014 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011015 int t;
11016
11017 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011018 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000011019
Eric Andersencb57d552001-06-28 07:25:16 +000011020 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000011021 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011022 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000011023 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000011024 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011025 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011026 n1->type = NIF;
11027 n1->nif.test = list(0);
11028 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011029 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011030 n1->nif.ifpart = list(0);
11031 n2 = n1;
11032 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011033 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000011034 n2 = n2->nif.elsepart;
11035 n2->type = NIF;
11036 n2->nif.test = list(0);
11037 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011038 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000011039 n2->nif.ifpart = list(0);
11040 }
11041 if (lasttoken == TELSE)
11042 n2->nif.elsepart = list(0);
11043 else {
11044 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011045 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011046 }
Eric Andersenc470f442003-07-28 09:56:35 +000011047 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000011048 break;
11049 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000011050 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000011051 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011052 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011053 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000011054 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011055 got = readtoken();
11056 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011057 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000011058 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011059 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011060 }
11061 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011062 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011063 break;
11064 }
11065 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000011066 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000011067 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011068 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000011069 n1->type = NFOR;
11070 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010011071 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011072 if (readtoken() == TIN) {
11073 app = &ap;
11074 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011075 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011076 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011077 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011078 n2->narg.text = wordtext;
11079 n2->narg.backquote = backquotelist;
11080 *app = n2;
11081 app = &n2->narg.next;
11082 }
11083 *app = NULL;
11084 n1->nfor.args = ap;
11085 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011086 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000011087 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011088 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011089 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011090 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011091 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011092 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000011093 n1->nfor.args = n2;
11094 /*
11095 * Newline or semicolon here is optional (but note
11096 * that the original Bourne shell only allowed NL).
11097 */
Ron Yorstonab80e012015-08-03 13:46:00 +010011098 if (lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011099 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011100 }
Eric Andersenc470f442003-07-28 09:56:35 +000011101 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011102 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011103 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011104 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011105 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011106 break;
11107 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011108 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011109 n1->type = NCASE;
11110 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011111 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011112 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011113 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011114 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011115 n2->narg.text = wordtext;
11116 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010011117 checkkwd = CHKNL | CHKKWD | CHKALIAS;
11118 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011119 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011120 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011121 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011122 checkkwd = CHKNL | CHKKWD;
11123 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011124 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011125 if (lasttoken == TLP)
11126 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011127 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011128 cp->type = NCLIST;
11129 app = &cp->nclist.pattern;
11130 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011131 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011132 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011133 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011134 ap->narg.text = wordtext;
11135 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011136 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011137 break;
11138 app = &ap->narg.next;
11139 readtoken();
11140 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011141 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011142 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011143 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011144 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011145
Eric Andersenc470f442003-07-28 09:56:35 +000011146 cpp = &cp->nclist.next;
11147
11148 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011149 t = readtoken();
11150 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011151 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011152 raise_error_unexpected_syntax(TENDCASE);
11153 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011154 }
Eric Andersenc470f442003-07-28 09:56:35 +000011155 }
Eric Andersencb57d552001-06-28 07:25:16 +000011156 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011157 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011158 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011159 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011160 n1->type = NSUBSHELL;
11161 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011162 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011163 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011164 break;
11165 case TBEGIN:
11166 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011167 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011168 break;
Ron Yorston95ebcf72015-11-03 09:42:23 +000011169 IF_ASH_BASH_COMPAT(case TFUNCTION:)
Eric Andersencb57d552001-06-28 07:25:16 +000011170 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011171 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011172 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011173 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011174 }
11175
Eric Andersenc470f442003-07-28 09:56:35 +000011176 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011177 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011178
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011179 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011180 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011181 checkkwd = CHKKWD | CHKALIAS;
11182 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011183 while (readtoken() == TREDIR) {
11184 *rpp = n2 = redirnode;
11185 rpp = &n2->nfile.next;
11186 parsefname();
11187 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011188 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011189 *rpp = NULL;
11190 if (redir) {
11191 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011192 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011193 n2->type = NREDIR;
11194 n2->nredir.n = n1;
11195 n1 = n2;
11196 }
11197 n1->nredir.redirect = redir;
11198 }
Eric Andersencb57d552001-06-28 07:25:16 +000011199 return n1;
11200}
11201
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011202#if ENABLE_ASH_BASH_COMPAT
11203static int decode_dollar_squote(void)
11204{
11205 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11206 int c, cnt;
11207 char *p;
11208 char buf[4];
11209
11210 c = pgetc();
11211 p = strchr(C_escapes, c);
11212 if (p) {
11213 buf[0] = c;
11214 p = buf;
11215 cnt = 3;
11216 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11217 do {
11218 c = pgetc();
11219 *++p = c;
11220 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11221 pungetc();
11222 } else if (c == 'x') { /* \xHH */
11223 do {
11224 c = pgetc();
11225 *++p = c;
11226 } while (isxdigit(c) && --cnt);
11227 pungetc();
11228 if (cnt == 3) { /* \x but next char is "bad" */
11229 c = 'x';
11230 goto unrecognized;
11231 }
11232 } else { /* simple seq like \\ or \t */
11233 p++;
11234 }
11235 *p = '\0';
11236 p = buf;
11237 c = bb_process_escape_sequence((void*)&p);
11238 } else { /* unrecognized "\z": print both chars unless ' or " */
11239 if (c != '\'' && c != '"') {
11240 unrecognized:
11241 c |= 0x100; /* "please encode \, then me" */
11242 }
11243 }
11244 return c;
11245}
11246#endif
11247
Eric Andersencb57d552001-06-28 07:25:16 +000011248/*
11249 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11250 * is not NULL, read a here document. In the latter case, eofmark is the
11251 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011252 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011253 * is the first character of the input token or document.
11254 *
11255 * Because C does not have internal subroutines, I have simulated them
11256 * using goto's to implement the subroutine linkage. The following macros
11257 * will run code that appears at the end of readtoken1.
11258 */
Eric Andersen2870d962001-07-02 17:27:21 +000011259#define CHECKEND() {goto checkend; checkend_return:;}
11260#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11261#define PARSESUB() {goto parsesub; parsesub_return:;}
11262#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11263#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11264#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011265static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011266readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011267{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011268 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011269 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011270 char *out;
11271 int len;
11272 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011273 struct nodelist *bqlist;
11274 smallint quotef;
11275 smallint dblquote;
11276 smallint oldstyle;
11277 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011278#if ENABLE_ASH_EXPAND_PRMT
11279 smallint pssyntax; /* we are expanding a prompt string */
11280#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011281 int varnest; /* levels of variables expansion */
11282 int arinest; /* levels of arithmetic expansion */
11283 int parenlevel; /* levels of parens in arithmetic */
11284 int dqvarnest; /* levels of variables expansion within double quotes */
11285
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011286 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011287
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011288 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011289 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011290 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011291 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011292#if ENABLE_ASH_EXPAND_PRMT
11293 pssyntax = (syntax == PSSYNTAX);
11294 if (pssyntax)
11295 syntax = DQSYNTAX;
11296#endif
11297 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011298 varnest = 0;
11299 arinest = 0;
11300 parenlevel = 0;
11301 dqvarnest = 0;
11302
11303 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011304 loop:
11305 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011306 CHECKEND(); /* set c to PEOF if at end of here document */
11307 for (;;) { /* until end of line or end of word */
11308 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11309 switch (SIT(c, syntax)) {
11310 case CNL: /* '\n' */
11311 if (syntax == BASESYNTAX)
11312 goto endword; /* exit outer loop */
11313 USTPUTC(c, out);
11314 g_parsefile->linno++;
11315 setprompt_if(doprompt, 2);
11316 c = pgetc();
11317 goto loop; /* continue outer loop */
11318 case CWORD:
11319 USTPUTC(c, out);
11320 break;
11321 case CCTL:
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011322#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011323 if (c == '\\' && bash_dollar_squote) {
11324 c = decode_dollar_squote();
Denys Vlasenko13f20912016-09-25 20:54:25 +020011325 if (c == '\0') {
11326 /* skip $'\000', $'\x00' (like bash) */
11327 break;
11328 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011329 if (c & 0x100) {
Denys Vlasenko13f20912016-09-25 20:54:25 +020011330 /* Unknown escape. Encode as '\z' */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011331 c = (unsigned char)c;
Denys Vlasenko13f20912016-09-25 20:54:25 +020011332 if (eofmark == NULL || dblquote)
11333 USTPUTC(CTLESC, out);
11334 USTPUTC('\\', out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011335 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011336 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011337#endif
Denys Vlasenko13f20912016-09-25 20:54:25 +020011338 if (eofmark == NULL || dblquote)
11339 USTPUTC(CTLESC, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011340 USTPUTC(c, out);
11341 break;
11342 case CBACK: /* backslash */
11343 c = pgetc_without_PEOA();
11344 if (c == PEOF) {
11345 USTPUTC(CTLESC, out);
11346 USTPUTC('\\', out);
11347 pungetc();
11348 } else if (c == '\n') {
11349 setprompt_if(doprompt, 2);
11350 } else {
11351#if ENABLE_ASH_EXPAND_PRMT
11352 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011353 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011354 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011355 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011356#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011357 /* Backslash is retained if we are in "str" and next char isn't special */
11358 if (dblquote
11359 && c != '\\'
11360 && c != '`'
11361 && c != '$'
11362 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011363 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011364 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011365 }
Ron Yorston549deab2015-05-18 09:57:51 +020011366 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011367 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011368 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011369 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011370 break;
11371 case CSQUOTE:
11372 syntax = SQSYNTAX;
11373 quotemark:
11374 if (eofmark == NULL) {
11375 USTPUTC(CTLQUOTEMARK, out);
11376 }
11377 break;
11378 case CDQUOTE:
11379 syntax = DQSYNTAX;
11380 dblquote = 1;
11381 goto quotemark;
11382 case CENDQUOTE:
11383 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011384 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011385 USTPUTC(c, out);
11386 } else {
11387 if (dqvarnest == 0) {
11388 syntax = BASESYNTAX;
11389 dblquote = 0;
11390 }
11391 quotef = 1;
11392 goto quotemark;
11393 }
11394 break;
11395 case CVAR: /* '$' */
11396 PARSESUB(); /* parse substitution */
11397 break;
11398 case CENDVAR: /* '}' */
11399 if (varnest > 0) {
11400 varnest--;
11401 if (dqvarnest > 0) {
11402 dqvarnest--;
11403 }
11404 c = CTLENDVAR;
11405 }
11406 USTPUTC(c, out);
11407 break;
11408#if ENABLE_SH_MATH_SUPPORT
11409 case CLP: /* '(' in arithmetic */
11410 parenlevel++;
11411 USTPUTC(c, out);
11412 break;
11413 case CRP: /* ')' in arithmetic */
11414 if (parenlevel > 0) {
11415 parenlevel--;
11416 } else {
11417 if (pgetc() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011418 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011419 if (--arinest == 0) {
11420 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011421 }
11422 } else {
11423 /*
11424 * unbalanced parens
11425 * (don't 2nd guess - no error)
11426 */
11427 pungetc();
11428 }
11429 }
11430 USTPUTC(c, out);
11431 break;
11432#endif
11433 case CBQUOTE: /* '`' */
11434 PARSEBACKQOLD();
11435 break;
11436 case CENDFILE:
11437 goto endword; /* exit outer loop */
11438 case CIGN:
11439 break;
11440 default:
11441 if (varnest == 0) {
11442#if ENABLE_ASH_BASH_COMPAT
11443 if (c == '&') {
11444 if (pgetc() == '>')
11445 c = 0x100 + '>'; /* flag &> */
11446 pungetc();
11447 }
11448#endif
11449 goto endword; /* exit outer loop */
11450 }
11451 IF_ASH_ALIAS(if (c != PEOA))
11452 USTPUTC(c, out);
11453 }
11454 c = pgetc_fast();
11455 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011456 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011457
Mike Frysinger98c52642009-04-02 10:02:37 +000011458#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011459 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011460 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011461#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011462 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011463 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011464 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011465 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011466 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011467 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011468 }
11469 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011470 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011471 out = stackblock();
11472 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011473 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011474 && quotef == 0
11475 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011476 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011477 PARSEREDIR(); /* passed as params: out, c */
11478 lasttoken = TREDIR;
11479 return lasttoken;
11480 }
11481 /* else: non-number X seen, interpret it
11482 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011483 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011484 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011485 }
11486 quoteflag = quotef;
11487 backquotelist = bqlist;
11488 grabstackblock(len);
11489 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011490 lasttoken = TWORD;
11491 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011492/* end of readtoken routine */
11493
Eric Andersencb57d552001-06-28 07:25:16 +000011494/*
11495 * Check to see whether we are at the end of the here document. When this
11496 * is called, c is set to the first character of the next input line. If
11497 * we are at the end of the here document, this routine sets the c to PEOF.
11498 */
Eric Andersenc470f442003-07-28 09:56:35 +000011499checkend: {
11500 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011501#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011502 if (c == PEOA)
11503 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011504#endif
11505 if (striptabs) {
11506 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011507 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011508 }
Eric Andersenc470f442003-07-28 09:56:35 +000011509 }
11510 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011511 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011512 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011513
Eric Andersenc470f442003-07-28 09:56:35 +000011514 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011515 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11516 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011517 if (*p == '\n' && *q == '\0') {
11518 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011519 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011520 needprompt = doprompt;
11521 } else {
11522 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011523 }
11524 }
11525 }
11526 }
Eric Andersenc470f442003-07-28 09:56:35 +000011527 goto checkend_return;
11528}
Eric Andersencb57d552001-06-28 07:25:16 +000011529
Eric Andersencb57d552001-06-28 07:25:16 +000011530/*
11531 * Parse a redirection operator. The variable "out" points to a string
11532 * specifying the fd to be redirected. The variable "c" contains the
11533 * first character of the redirection operator.
11534 */
Eric Andersenc470f442003-07-28 09:56:35 +000011535parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011536 /* out is already checked to be a valid number or "" */
11537 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011538 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011539
Denis Vlasenko597906c2008-02-20 16:38:54 +000011540 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011541 if (c == '>') {
11542 np->nfile.fd = 1;
11543 c = pgetc();
11544 if (c == '>')
11545 np->type = NAPPEND;
11546 else if (c == '|')
11547 np->type = NCLOBBER;
11548 else if (c == '&')
11549 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011550 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011551 else {
11552 np->type = NTO;
11553 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011554 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011555 }
11556#if ENABLE_ASH_BASH_COMPAT
11557 else if (c == 0x100 + '>') { /* this flags &> redirection */
11558 np->nfile.fd = 1;
11559 pgetc(); /* this is '>', no need to check */
11560 np->type = NTO2;
11561 }
11562#endif
11563 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011564 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011565 c = pgetc();
11566 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011567 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011568 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011569 np = stzalloc(sizeof(struct nhere));
11570 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011571 }
11572 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011573 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011574 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011575 c = pgetc();
11576 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011577 heredoc->striptabs = 1;
11578 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011579 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011580 pungetc();
11581 }
11582 break;
11583
11584 case '&':
11585 np->type = NFROMFD;
11586 break;
11587
11588 case '>':
11589 np->type = NFROMTO;
11590 break;
11591
11592 default:
11593 np->type = NFROM;
11594 pungetc();
11595 break;
11596 }
Eric Andersencb57d552001-06-28 07:25:16 +000011597 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011598 if (fd >= 0)
11599 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011600 redirnode = np;
11601 goto parseredir_return;
11602}
Eric Andersencb57d552001-06-28 07:25:16 +000011603
Eric Andersencb57d552001-06-28 07:25:16 +000011604/*
11605 * Parse a substitution. At this point, we have read the dollar sign
11606 * and nothing else.
11607 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011608
11609/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11610 * (assuming ascii char codes, as the original implementation did) */
11611#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011612 (((unsigned)(c) - 33 < 32) \
11613 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011614parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011615 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011616 int typeloc;
11617 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011618
Eric Andersenc470f442003-07-28 09:56:35 +000011619 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011620 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011621 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011622 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011623#if ENABLE_ASH_BASH_COMPAT
Ron Yorston84ba50c2016-04-03 22:43:14 +010011624 if (syntax != DQSYNTAX && c == '\'')
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011625 bash_dollar_squote = 1;
11626 else
11627#endif
11628 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011629 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011630 } else if (c == '(') {
11631 /* $(command) or $((arith)) */
Eric Andersenc470f442003-07-28 09:56:35 +000011632 if (pgetc() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011633#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011634 PARSEARITH();
11635#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011636 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011637#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011638 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011639 pungetc();
11640 PARSEBACKQNEW();
11641 }
11642 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011643 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011644 USTPUTC(CTLVAR, out);
11645 typeloc = out - (char *)stackblock();
11646 USTPUTC(VSNORMAL, out);
11647 subtype = VSNORMAL;
11648 if (c == '{') {
11649 c = pgetc();
11650 if (c == '#') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011651 c = pgetc();
11652 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011653 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011654 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011655 subtype = VSLENGTH; /* ${#VAR} */
11656 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011657 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011658 }
Eric Andersenc470f442003-07-28 09:56:35 +000011659 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011660 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011661 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011662 do {
11663 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011664 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011665 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011666 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011667 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011668 do {
11669 STPUTC(c, out);
11670 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011671 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011672 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011673 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011674 USTPUTC(c, out);
11675 c = pgetc();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011676 } else {
11677 badsub:
11678 raise_error_syntax("bad substitution");
11679 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011680 if (c != '}' && subtype == VSLENGTH) {
11681 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011682 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011683 }
Eric Andersencb57d552001-06-28 07:25:16 +000011684
Eric Andersenc470f442003-07-28 09:56:35 +000011685 STPUTC('=', out);
11686 flags = 0;
11687 if (subtype == 0) {
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011688 static const char types[] ALIGN1 = "}-+?=";
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011689 /* ${VAR...} but not $VAR or ${#VAR} */
11690 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011691 switch (c) {
11692 case ':':
Eric Andersenc470f442003-07-28 09:56:35 +000011693 c = pgetc();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011694#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkof8ddbe12016-07-25 03:56:00 +020011695 /* This check is only needed to not misinterpret
11696 * ${VAR:-WORD}, ${VAR:+WORD}, ${VAR:=WORD}, ${VAR:?WORD}
11697 * constructs.
11698 */
11699 if (!strchr(types, c)) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011700 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011701 pungetc();
11702 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011703 }
11704#endif
11705 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011706 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011707 default: {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011708 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011709 if (p == NULL)
11710 goto badsub;
11711 subtype = p - types + VSNORMAL;
11712 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011713 }
Eric Andersenc470f442003-07-28 09:56:35 +000011714 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011715 case '#': {
11716 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011717 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011718 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011719 if (c != cc)
11720 goto do_pungetc;
11721 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011722 break;
11723 }
11724#if ENABLE_ASH_BASH_COMPAT
11725 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011726 /* ${v/[/]pattern/repl} */
11727//TODO: encode pattern and repl separately.
11728// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011729 subtype = VSREPLACE;
11730 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011731 if (c != '/')
11732 goto do_pungetc;
11733 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011734 break;
11735#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011736 }
Eric Andersenc470f442003-07-28 09:56:35 +000011737 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011738 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011739 pungetc();
11740 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011741 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011742 if (subtype != VSNORMAL) {
11743 varnest++;
Ron Yorston7e4ed262015-05-18 09:54:43 +020011744 if (dblquote) {
Eric Andersenc470f442003-07-28 09:56:35 +000011745 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011746 }
11747 }
11748 }
Eric Andersenc470f442003-07-28 09:56:35 +000011749 goto parsesub_return;
11750}
Eric Andersencb57d552001-06-28 07:25:16 +000011751
Eric Andersencb57d552001-06-28 07:25:16 +000011752/*
11753 * Called to parse command substitutions. Newstyle is set if the command
11754 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11755 * list of commands (passed by reference), and savelen is the number of
11756 * characters on the top of the stack which must be preserved.
11757 */
Eric Andersenc470f442003-07-28 09:56:35 +000011758parsebackq: {
11759 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011760 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011761 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011762 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011763 smallint saveprompt = 0;
11764
Eric Andersenc470f442003-07-28 09:56:35 +000011765 str = NULL;
11766 savelen = out - (char *)stackblock();
11767 if (savelen > 0) {
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011768 /*
11769 * FIXME: this can allocate very large block on stack and SEGV.
11770 * Example:
11771 * echo "..<100kbytes>..`true` $(true) `true` ..."
Denys Vlasenko73737592016-09-17 20:58:22 +020011772 * allocates 100kb for every command subst. With about
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011773 * a hundred command substitutions stack overflows.
11774 * With larger prepended string, SEGV happens sooner.
11775 */
Ron Yorston072fc602015-07-01 16:46:18 +010011776 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011777 memcpy(str, stackblock(), savelen);
11778 }
Denys Vlasenko7bc3d392016-09-17 20:53:47 +020011779
Eric Andersenc470f442003-07-28 09:56:35 +000011780 if (oldstyle) {
11781 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011782 * treatment to some slashes, and then push the string and
11783 * reread it as input, interpreting it normally.
11784 */
Eric Andersenc470f442003-07-28 09:56:35 +000011785 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011786 size_t psavelen;
11787 char *pstr;
11788
Eric Andersenc470f442003-07-28 09:56:35 +000011789 STARTSTACKSTR(pout);
11790 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011791 int pc;
11792
11793 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011794 pc = pgetc();
11795 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011796 case '`':
11797 goto done;
11798
11799 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011800 pc = pgetc();
11801 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011802 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011803 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011804 /*
11805 * If eating a newline, avoid putting
11806 * the newline into the new character
11807 * stream (via the STPUTC after the
11808 * switch).
11809 */
11810 continue;
11811 }
11812 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011813 && (!dblquote || pc != '"')
11814 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011815 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011816 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011817 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011818 break;
11819 }
11820 /* fall through */
11821
11822 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011823 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011824 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011825 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011826
11827 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011828 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011829 needprompt = doprompt;
11830 break;
11831
11832 default:
11833 break;
11834 }
11835 STPUTC(pc, pout);
11836 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011837 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011838 STPUTC('\0', pout);
11839 psavelen = pout - (char *)stackblock();
11840 if (psavelen > 0) {
11841 pstr = grabstackstr(pout);
11842 setinputstring(pstr);
11843 }
11844 }
11845 nlpp = &bqlist;
11846 while (*nlpp)
11847 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011848 *nlpp = stzalloc(sizeof(**nlpp));
11849 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011850
11851 if (oldstyle) {
11852 saveprompt = doprompt;
11853 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011854 }
11855
Eric Andersenc470f442003-07-28 09:56:35 +000011856 n = list(2);
11857
11858 if (oldstyle)
11859 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011860 else if (readtoken() != TRP)
11861 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011862
11863 (*nlpp)->n = n;
11864 if (oldstyle) {
11865 /*
11866 * Start reading from old file again, ignoring any pushed back
11867 * tokens left from the backquote parsing
11868 */
11869 popfile();
11870 tokpushback = 0;
11871 }
11872 while (stackblocksize() <= savelen)
11873 growstackblock();
11874 STARTSTACKSTR(out);
11875 if (str) {
11876 memcpy(out, str, savelen);
11877 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011878 }
Ron Yorston549deab2015-05-18 09:57:51 +020011879 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011880 if (oldstyle)
11881 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011882 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011883}
11884
Mike Frysinger98c52642009-04-02 10:02:37 +000011885#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011886/*
11887 * Parse an arithmetic expansion (indicate start of one and set state)
11888 */
Eric Andersenc470f442003-07-28 09:56:35 +000011889parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011890 if (++arinest == 1) {
11891 prevsyntax = syntax;
11892 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011893 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011894 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011895 goto parsearith_return;
11896}
11897#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011898} /* end of readtoken */
11899
Eric Andersencb57d552001-06-28 07:25:16 +000011900/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011901 * Read the next input token.
11902 * If the token is a word, we set backquotelist to the list of cmds in
11903 * backquotes. We set quoteflag to true if any part of the word was
11904 * quoted.
11905 * If the token is TREDIR, then we set redirnode to a structure containing
11906 * the redirection.
11907 * In all cases, the variable startlinno is set to the number of the line
11908 * on which the token starts.
11909 *
11910 * [Change comment: here documents and internal procedures]
11911 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11912 * word parsing code into a separate routine. In this case, readtoken
11913 * doesn't need to have any internal procedures, but parseword does.
11914 * We could also make parseoperator in essence the main routine, and
11915 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011916 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011917#define NEW_xxreadtoken
11918#ifdef NEW_xxreadtoken
11919/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011920static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011921 '\n', '(', ')', /* singles */
11922 '&', '|', ';', /* doubles */
11923 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011924};
Eric Andersencb57d552001-06-28 07:25:16 +000011925
Denis Vlasenko834dee72008-10-07 09:18:30 +000011926#define xxreadtoken_singles 3
11927#define xxreadtoken_doubles 3
11928
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011929static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011930 TNL, TLP, TRP, /* only single occurrence allowed */
11931 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11932 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011933 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011934};
11935
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011936static int
11937xxreadtoken(void)
11938{
11939 int c;
11940
11941 if (tokpushback) {
11942 tokpushback = 0;
11943 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011944 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011945 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011946 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011947 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011948 c = pgetc_fast();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011949 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011950 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011951
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011952 if (c == '#') {
11953 while ((c = pgetc()) != '\n' && c != PEOF)
11954 continue;
11955 pungetc();
11956 } else if (c == '\\') {
11957 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011958 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011959 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011960 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011961 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011962 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011963 } else {
11964 const char *p;
11965
11966 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11967 if (c != PEOF) {
11968 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011969 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011970 needprompt = doprompt;
11971 }
11972
11973 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011974 if (p == NULL)
11975 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011976
Denis Vlasenko834dee72008-10-07 09:18:30 +000011977 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11978 int cc = pgetc();
11979 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011980 p += xxreadtoken_doubles + 1;
11981 } else {
11982 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011983#if ENABLE_ASH_BASH_COMPAT
11984 if (c == '&' && cc == '>') /* &> */
11985 break; /* return readtoken1(...) */
11986#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011987 }
11988 }
11989 }
11990 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11991 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011992 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011993 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011994
11995 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011996}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011997#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011998#define RETURN(token) return lasttoken = token
11999static int
12000xxreadtoken(void)
12001{
12002 int c;
12003
12004 if (tokpushback) {
12005 tokpushback = 0;
12006 return lasttoken;
12007 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020012008 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012009 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012010 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000012011 c = pgetc_fast();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012012 switch (c) {
12013 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010012014 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012015 continue;
12016 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000012017 while ((c = pgetc()) != '\n' && c != PEOF)
12018 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012019 pungetc();
12020 continue;
12021 case '\\':
12022 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012023 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012024 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012025 continue;
12026 }
12027 pungetc();
12028 goto breakloop;
12029 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000012030 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012031 needprompt = doprompt;
12032 RETURN(TNL);
12033 case PEOF:
12034 RETURN(TEOF);
12035 case '&':
12036 if (pgetc() == '&')
12037 RETURN(TAND);
12038 pungetc();
12039 RETURN(TBACKGND);
12040 case '|':
12041 if (pgetc() == '|')
12042 RETURN(TOR);
12043 pungetc();
12044 RETURN(TPIPE);
12045 case ';':
12046 if (pgetc() == ';')
12047 RETURN(TENDCASE);
12048 pungetc();
12049 RETURN(TSEMI);
12050 case '(':
12051 RETURN(TLP);
12052 case ')':
12053 RETURN(TRP);
12054 default:
12055 goto breakloop;
12056 }
12057 }
12058 breakloop:
12059 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12060#undef RETURN
12061}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012062#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012063
12064static int
12065readtoken(void)
12066{
12067 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000012068 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012069#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012070 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012071#endif
12072
12073#if ENABLE_ASH_ALIAS
12074 top:
12075#endif
12076
12077 t = xxreadtoken();
12078
12079 /*
12080 * eat newlines
12081 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012082 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012083 while (t == TNL) {
12084 parseheredoc();
12085 t = xxreadtoken();
12086 }
12087 }
12088
12089 if (t != TWORD || quoteflag) {
12090 goto out;
12091 }
12092
12093 /*
12094 * check for keywords
12095 */
Ron Yorston713f07d2015-10-29 16:44:56 +000012096 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012097 const char *const *pp;
12098
12099 pp = findkwd(wordtext);
12100 if (pp) {
12101 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012102 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012103 goto out;
12104 }
12105 }
12106
12107 if (checkkwd & CHKALIAS) {
12108#if ENABLE_ASH_ALIAS
12109 struct alias *ap;
12110 ap = lookupalias(wordtext, 1);
12111 if (ap != NULL) {
12112 if (*ap->val) {
12113 pushstring(ap->val, ap);
12114 }
12115 goto top;
12116 }
12117#endif
12118 }
12119 out:
12120 checkkwd = 0;
12121#if DEBUG
12122 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012123 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012124 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012125 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012126#endif
12127 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012128}
12129
Ron Yorstonc0e00762015-10-29 11:30:55 +000012130static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000012131peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012132{
12133 int t;
12134
12135 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012136 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012137 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012138}
Eric Andersencb57d552001-06-28 07:25:16 +000012139
12140/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012141 * Read and parse a command. Returns NODE_EOF on end of file.
12142 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012143 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012144static union node *
12145parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012146{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012147 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000012148 checkkwd = 0;
12149 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012150 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012151 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012152 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012153 return list(1);
12154}
12155
12156/*
12157 * Input any here documents.
12158 */
12159static void
12160parseheredoc(void)
12161{
12162 struct heredoc *here;
12163 union node *n;
12164
12165 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012166 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012167
12168 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012169 setprompt_if(needprompt, 2);
12170 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012171 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012172 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012173 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012174 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012175 n->narg.text = wordtext;
12176 n->narg.backquote = backquotelist;
12177 here->here->nhere.doc = n;
12178 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012179 }
Eric Andersencb57d552001-06-28 07:25:16 +000012180}
12181
12182
12183/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012184 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012185 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012186#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012187static const char *
12188expandstr(const char *ps)
12189{
12190 union node n;
12191
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012192 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12193 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012194 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012195 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012196 popfile();
12197
12198 n.narg.type = NARG;
12199 n.narg.next = NULL;
12200 n.narg.text = wordtext;
12201 n.narg.backquote = backquotelist;
12202
Ron Yorston549deab2015-05-18 09:57:51 +020012203 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012204 return stackblock();
12205}
12206#endif
12207
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012208/*
12209 * Execute a command or commands contained in a string.
12210 */
12211static int
12212evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012213{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012214 union node *n;
12215 struct stackmark smark;
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012216 int status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012217
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012218 s = sstrdup(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012219 setinputstring(s);
12220 setstackmark(&smark);
12221
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012222 status = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012223 while ((n = parsecmd(0)) != NODE_EOF) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012224 int i;
12225
12226 i = evaltree(n, 0);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012227 if (n)
12228 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012229 popstackmark(&smark);
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012230 if (evalskip)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012231 break;
12232 }
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012233 popstackmark(&smark);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012234 popfile();
Denys Vlasenko8e2bc472016-09-28 23:02:57 +020012235 stunalloc(s);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012236
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012237 evalskip &= mask;
12238 return status;
Eric Andersenc470f442003-07-28 09:56:35 +000012239}
12240
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012241/*
12242 * The eval command.
12243 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012244static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012245evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012246{
12247 char *p;
12248 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012249
Denis Vlasenko68404f12008-03-17 09:00:54 +000012250 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012251 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012252 argv += 2;
12253 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012254 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012255 for (;;) {
12256 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012257 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012258 if (p == NULL)
12259 break;
12260 STPUTC(' ', concat);
12261 }
12262 STPUTC('\0', concat);
12263 p = grabstackstr(concat);
12264 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012265 return evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012266 }
Denys Vlasenko928e2a72016-09-29 00:30:31 +020012267 return 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012268}
12269
12270/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012271 * Read and execute commands.
12272 * "Top" is nonzero for the top level command loop;
12273 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012274 */
12275static int
12276cmdloop(int top)
12277{
12278 union node *n;
12279 struct stackmark smark;
12280 int inter;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012281 int status = 0;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012282 int numeof = 0;
12283
12284 TRACE(("cmdloop(%d) called\n", top));
12285 for (;;) {
12286 int skip;
12287
12288 setstackmark(&smark);
12289#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012290 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012291 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012292#endif
12293 inter = 0;
12294 if (iflag && top) {
12295 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012296 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012297 }
12298 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012299#if DEBUG
12300 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012301 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012302#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012303 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012304 if (!top || numeof >= 50)
12305 break;
12306 if (!stoppedjobs()) {
12307 if (!Iflag)
12308 break;
12309 out2str("\nUse \"exit\" to leave shell.\n");
12310 }
12311 numeof++;
12312 } else if (nflag == 0) {
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012313 int i;
12314
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012315 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12316 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012317 numeof = 0;
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012318 i = evaltree(n, 0);
12319 if (n)
12320 status = i;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012321 }
12322 popstackmark(&smark);
12323 skip = evalskip;
12324
12325 if (skip) {
12326 evalskip = 0;
12327 return skip & SKIPEVAL;
12328 }
12329 }
Denys Vlasenkoeb17b6f2016-09-28 19:41:57 +020012330 return status;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012331}
12332
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012333/*
12334 * Take commands from a file. To be compatible we should do a path
12335 * search for the file, which is necessary to find sub-commands.
12336 */
12337static char *
12338find_dot_file(char *name)
12339{
12340 char *fullname;
12341 const char *path = pathval();
12342 struct stat statb;
12343
12344 /* don't try this for absolute or relative paths */
12345 if (strchr(name, '/'))
12346 return name;
12347
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012348 /* IIRC standards do not say whether . is to be searched.
12349 * And it is even smaller this way, making it unconditional for now:
12350 */
12351 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12352 fullname = name;
12353 goto try_cur_dir;
12354 }
12355
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012356 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012357 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012358 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12359 /*
12360 * Don't bother freeing here, since it will
12361 * be freed by the caller.
12362 */
12363 return fullname;
12364 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012365 if (fullname != name)
12366 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012367 }
12368
12369 /* not found in the PATH */
12370 ash_msg_and_raise_error("%s: not found", name);
12371 /* NOTREACHED */
12372}
12373
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012374static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012375dotcmd(int argc, char **argv)
12376{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012377 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012378 struct strlist *sp;
12379 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012380
12381 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012382 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012383
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012384 if (!argv[1]) {
12385 /* bash says: "bash: .: filename argument required" */
12386 return 2; /* bash compat */
12387 }
12388
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012389 /* "false; . empty_file; echo $?" should print 0, not 1: */
12390 exitstatus = 0;
12391
Denys Vlasenko091f8312013-03-17 14:25:22 +010012392 /* This aborts if file isn't found, which is POSIXly correct.
12393 * bash returns exitcode 1 instead.
12394 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012395 fullname = find_dot_file(argv[1]);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012396 argv += 2;
12397 argc -= 2;
12398 if (argc) { /* argc > 0, argv[0] != NULL */
12399 saveparam = shellparam;
12400 shellparam.malloced = 0;
12401 shellparam.nparam = argc;
12402 shellparam.p = argv;
12403 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012404
Denys Vlasenko091f8312013-03-17 14:25:22 +010012405 /* This aborts if file can't be opened, which is POSIXly correct.
12406 * bash returns exitcode 1 instead.
12407 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012408 setinputfile(fullname, INPUT_PUSH_FILE);
12409 commandname = fullname;
12410 cmdloop(0);
12411 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012412
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012413 if (argc) {
12414 freeparam(&shellparam);
12415 shellparam = saveparam;
12416 };
12417
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012418 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012419}
12420
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012421static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012422exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012423{
12424 if (stoppedjobs())
12425 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012426 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012427 exitstatus = number(argv[1]);
12428 raise_exception(EXEXIT);
12429 /* NOTREACHED */
12430}
12431
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012432/*
12433 * Read a file containing shell functions.
12434 */
12435static void
12436readcmdfile(char *name)
12437{
12438 setinputfile(name, INPUT_PUSH_FILE);
12439 cmdloop(0);
12440 popfile();
12441}
12442
12443
Denis Vlasenkocc571512007-02-23 21:10:35 +000012444/* ============ find_command inplementation */
12445
12446/*
12447 * Resolve a command name. If you change this routine, you may have to
12448 * change the shellexec routine as well.
12449 */
12450static void
12451find_command(char *name, struct cmdentry *entry, int act, const char *path)
12452{
12453 struct tblentry *cmdp;
12454 int idx;
12455 int prev;
12456 char *fullname;
12457 struct stat statb;
12458 int e;
12459 int updatetbl;
12460 struct builtincmd *bcmd;
12461
12462 /* If name contains a slash, don't use PATH or hash table */
12463 if (strchr(name, '/') != NULL) {
12464 entry->u.index = -1;
12465 if (act & DO_ABS) {
12466 while (stat(name, &statb) < 0) {
12467#ifdef SYSV
12468 if (errno == EINTR)
12469 continue;
12470#endif
12471 entry->cmdtype = CMDUNKNOWN;
12472 return;
12473 }
12474 }
12475 entry->cmdtype = CMDNORMAL;
12476 return;
12477 }
12478
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012479/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012480
12481 updatetbl = (path == pathval());
12482 if (!updatetbl) {
12483 act |= DO_ALTPATH;
12484 if (strstr(path, "%builtin") != NULL)
12485 act |= DO_ALTBLTIN;
12486 }
12487
12488 /* If name is in the table, check answer will be ok */
12489 cmdp = cmdlookup(name, 0);
12490 if (cmdp != NULL) {
12491 int bit;
12492
12493 switch (cmdp->cmdtype) {
12494 default:
12495#if DEBUG
12496 abort();
12497#endif
12498 case CMDNORMAL:
12499 bit = DO_ALTPATH;
12500 break;
12501 case CMDFUNCTION:
12502 bit = DO_NOFUNC;
12503 break;
12504 case CMDBUILTIN:
12505 bit = DO_ALTBLTIN;
12506 break;
12507 }
12508 if (act & bit) {
12509 updatetbl = 0;
12510 cmdp = NULL;
12511 } else if (cmdp->rehash == 0)
12512 /* if not invalidated by cd, we're done */
12513 goto success;
12514 }
12515
12516 /* If %builtin not in path, check for builtin next */
12517 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012518 if (bcmd) {
12519 if (IS_BUILTIN_REGULAR(bcmd))
12520 goto builtin_success;
12521 if (act & DO_ALTPATH) {
12522 if (!(act & DO_ALTBLTIN))
12523 goto builtin_success;
12524 } else if (builtinloc <= 0) {
12525 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012526 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012527 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012528
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012529#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012530 {
12531 int applet_no = find_applet_by_name(name);
12532 if (applet_no >= 0) {
12533 entry->cmdtype = CMDNORMAL;
12534 entry->u.index = -2 - applet_no;
12535 return;
12536 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012537 }
12538#endif
12539
Denis Vlasenkocc571512007-02-23 21:10:35 +000012540 /* We have to search path. */
12541 prev = -1; /* where to start */
12542 if (cmdp && cmdp->rehash) { /* doing a rehash */
12543 if (cmdp->cmdtype == CMDBUILTIN)
12544 prev = builtinloc;
12545 else
12546 prev = cmdp->param.index;
12547 }
12548
12549 e = ENOENT;
12550 idx = -1;
12551 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012552 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012553 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012554 /* NB: code below will still use fullname
12555 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012556 idx++;
12557 if (pathopt) {
12558 if (prefix(pathopt, "builtin")) {
12559 if (bcmd)
12560 goto builtin_success;
12561 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012562 }
12563 if ((act & DO_NOFUNC)
12564 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012565 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012566 continue;
12567 }
12568 }
12569 /* if rehash, don't redo absolute path names */
12570 if (fullname[0] == '/' && idx <= prev) {
12571 if (idx < prev)
12572 continue;
12573 TRACE(("searchexec \"%s\": no change\n", name));
12574 goto success;
12575 }
12576 while (stat(fullname, &statb) < 0) {
12577#ifdef SYSV
12578 if (errno == EINTR)
12579 continue;
12580#endif
12581 if (errno != ENOENT && errno != ENOTDIR)
12582 e = errno;
12583 goto loop;
12584 }
12585 e = EACCES; /* if we fail, this will be the error */
12586 if (!S_ISREG(statb.st_mode))
12587 continue;
12588 if (pathopt) { /* this is a %func directory */
12589 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012590 /* NB: stalloc will return space pointed by fullname
12591 * (because we don't have any intervening allocations
12592 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012593 readcmdfile(fullname);
12594 cmdp = cmdlookup(name, 0);
12595 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12596 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12597 stunalloc(fullname);
12598 goto success;
12599 }
12600 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12601 if (!updatetbl) {
12602 entry->cmdtype = CMDNORMAL;
12603 entry->u.index = idx;
12604 return;
12605 }
12606 INT_OFF;
12607 cmdp = cmdlookup(name, 1);
12608 cmdp->cmdtype = CMDNORMAL;
12609 cmdp->param.index = idx;
12610 INT_ON;
12611 goto success;
12612 }
12613
12614 /* We failed. If there was an entry for this command, delete it */
12615 if (cmdp && updatetbl)
12616 delete_cmd_entry();
12617 if (act & DO_ERR)
12618 ash_msg("%s: %s", name, errmsg(e, "not found"));
12619 entry->cmdtype = CMDUNKNOWN;
12620 return;
12621
12622 builtin_success:
12623 if (!updatetbl) {
12624 entry->cmdtype = CMDBUILTIN;
12625 entry->u.cmd = bcmd;
12626 return;
12627 }
12628 INT_OFF;
12629 cmdp = cmdlookup(name, 1);
12630 cmdp->cmdtype = CMDBUILTIN;
12631 cmdp->param.cmd = bcmd;
12632 INT_ON;
12633 success:
12634 cmdp->rehash = 0;
12635 entry->cmdtype = cmdp->cmdtype;
12636 entry->u = cmdp->param;
12637}
12638
12639
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012640/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012641
Eric Andersencb57d552001-06-28 07:25:16 +000012642/*
Eric Andersencb57d552001-06-28 07:25:16 +000012643 * The trap builtin.
12644 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012645static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012646trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012647{
12648 char *action;
12649 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012650 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012651
Eric Andersenc470f442003-07-28 09:56:35 +000012652 nextopt(nullstr);
12653 ap = argptr;
12654 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012655 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012656 char *tr = trap_ptr[signo];
12657 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012658 /* note: bash adds "SIG", but only if invoked
12659 * as "bash". If called as "sh", or if set -o posix,
12660 * then it prints short signal names.
12661 * We are printing short names: */
12662 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012663 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012664 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012665 /* trap_ptr != trap only if we are in special-cased `trap` code.
12666 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012667 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012668 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012669 }
12670 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012671 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012672 if (trap_ptr != trap) {
12673 free(trap_ptr);
12674 trap_ptr = trap;
12675 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012676 */
Eric Andersencb57d552001-06-28 07:25:16 +000012677 return 0;
12678 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012679
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012680 action = NULL;
12681 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012682 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012683 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012684 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012685 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012686 if (signo < 0) {
12687 /* Mimic bash message exactly */
12688 ash_msg("%s: invalid signal specification", *ap);
12689 exitcode = 1;
12690 goto next;
12691 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012692 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012693 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012694 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012695 action = NULL;
12696 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012697 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012698 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012699 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012700 if (action)
12701 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012702 trap[signo] = action;
12703 if (signo != 0)
12704 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012705 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012706 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012707 ap++;
12708 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012709 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012710}
12711
Eric Andersenc470f442003-07-28 09:56:35 +000012712
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012713/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012714
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012715#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012716static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012717helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012718{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012719 unsigned col;
12720 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012721
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012722 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012723 "Built-in commands:\n"
12724 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012725 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012726 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012727 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012728 if (col > 60) {
12729 out1fmt("\n");
12730 col = 0;
12731 }
12732 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012733# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012734 {
12735 const char *a = applet_names;
12736 while (*a) {
12737 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12738 if (col > 60) {
12739 out1fmt("\n");
12740 col = 0;
12741 }
Ron Yorston2b919582016-04-08 11:57:20 +010012742 while (*a++ != '\0')
12743 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000012744 }
12745 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012746# endif
Eric Andersenc470f442003-07-28 09:56:35 +000012747 out1fmt("\n\n");
12748 return EXIT_SUCCESS;
12749}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012750#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012751
Flemming Madsend96ffda2013-04-07 18:47:24 +020012752#if MAX_HISTORY
12753static int FAST_FUNC
12754historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12755{
12756 show_history(line_input_state);
12757 return EXIT_SUCCESS;
12758}
12759#endif
12760
Eric Andersencb57d552001-06-28 07:25:16 +000012761/*
Eric Andersencb57d552001-06-28 07:25:16 +000012762 * The export and readonly commands.
12763 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012764static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012765exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012766{
12767 struct var *vp;
12768 char *name;
12769 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012770 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012771 char opt;
12772 int flag;
12773 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012774
Denys Vlasenkod5275882012-10-01 13:41:17 +020012775 /* "readonly" in bash accepts, but ignores -n.
12776 * We do the same: it saves a conditional in nextopt's param.
12777 */
12778 flag_off = 0;
12779 while ((opt = nextopt("np")) != '\0') {
12780 if (opt == 'n')
12781 flag_off = VEXPORT;
12782 }
12783 flag = VEXPORT;
12784 if (argv[0][0] == 'r') {
12785 flag = VREADONLY;
12786 flag_off = 0; /* readonly ignores -n */
12787 }
12788 flag_off = ~flag_off;
12789
12790 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12791 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012792 aptr = argptr;
12793 name = *aptr;
12794 if (name) {
12795 do {
12796 p = strchr(name, '=');
12797 if (p != NULL) {
12798 p++;
12799 } else {
12800 vp = *findvar(hashvar(name), name);
12801 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012802 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012803 continue;
12804 }
Eric Andersencb57d552001-06-28 07:25:16 +000012805 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012806 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012807 } while ((name = *++aptr) != NULL);
12808 return 0;
12809 }
Eric Andersencb57d552001-06-28 07:25:16 +000012810 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012811
12812 /* No arguments. Show the list of exported or readonly vars.
12813 * -n is ignored.
12814 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012815 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012816 return 0;
12817}
12818
Eric Andersencb57d552001-06-28 07:25:16 +000012819/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012820 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012821 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012822static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012823unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012824{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012825 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012826
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012827 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012828 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012829 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012830}
12831
Eric Andersencb57d552001-06-28 07:25:16 +000012832/*
Eric Andersencb57d552001-06-28 07:25:16 +000012833 * The unset builtin command. We unset the function before we unset the
12834 * variable to allow a function to be unset when there is a readonly variable
12835 * with the same name.
12836 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012837static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012838unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012839{
12840 char **ap;
12841 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012842 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012843 int ret = 0;
12844
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012845 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012846 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012847 }
Eric Andersencb57d552001-06-28 07:25:16 +000012848
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012849 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012850 if (flag != 'f') {
12851 i = unsetvar(*ap);
12852 ret |= i;
12853 if (!(i & 2))
12854 continue;
12855 }
12856 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012857 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012858 }
Eric Andersenc470f442003-07-28 09:56:35 +000012859 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012860}
12861
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012862static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012863 ' ', offsetof(struct tms, tms_utime),
12864 '\n', offsetof(struct tms, tms_stime),
12865 ' ', offsetof(struct tms, tms_cutime),
12866 '\n', offsetof(struct tms, tms_cstime),
12867 0
12868};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012869static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012870timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012871{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012872 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012873 const unsigned char *p;
12874 struct tms buf;
12875
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012876 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012877 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012878
12879 p = timescmd_str;
12880 do {
12881 t = *(clock_t *)(((char *) &buf) + p[1]);
12882 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012883 t = t % clk_tck;
12884 out1fmt("%lum%lu.%03lus%c",
12885 s / 60, s % 60,
12886 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012887 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012888 p += 2;
12889 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012890
Eric Andersencb57d552001-06-28 07:25:16 +000012891 return 0;
12892}
12893
Mike Frysinger98c52642009-04-02 10:02:37 +000012894#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012895/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012896 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012897 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012898 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012899 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012900 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012901static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012902letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012903{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012904 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012905
Denis Vlasenko68404f12008-03-17 09:00:54 +000012906 argv++;
12907 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012908 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012909 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012910 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012911 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012912
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012913 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012914}
Eric Andersenc470f442003-07-28 09:56:35 +000012915#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012916
Eric Andersenc470f442003-07-28 09:56:35 +000012917/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012918 * The read builtin. Options:
12919 * -r Do not interpret '\' specially
12920 * -s Turn off echo (tty only)
12921 * -n NCHARS Read NCHARS max
12922 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12923 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12924 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012925 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012926 * TODO: bash also has:
12927 * -a ARRAY Read into array[0],[1],etc
12928 * -d DELIM End on DELIM char, not newline
12929 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012930 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012931static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012932readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012933{
Denys Vlasenko73067272010-01-12 22:11:24 +010012934 char *opt_n = NULL;
12935 char *opt_p = NULL;
12936 char *opt_t = NULL;
12937 char *opt_u = NULL;
12938 int read_flags = 0;
12939 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012940 int i;
12941
Denys Vlasenko73067272010-01-12 22:11:24 +010012942 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012943 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012944 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012945 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012946 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012947 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012948 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012949 break;
12950 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012951 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012952 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012953 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012954 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012955 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012956 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012957 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012958 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012959 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012960 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012961 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012962 default:
12963 break;
12964 }
Eric Andersenc470f442003-07-28 09:56:35 +000012965 }
Paul Fox02eb9342005-09-07 16:56:02 +000012966
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012967 /* "read -s" needs to save/restore termios, can't allow ^C
12968 * to jump out of it.
12969 */
12970 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012971 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010012972 argptr,
12973 bltinlookup("IFS"), /* can be NULL */
12974 read_flags,
12975 opt_n,
12976 opt_p,
12977 opt_t,
12978 opt_u
12979 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012980 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012981
Denys Vlasenko73067272010-01-12 22:11:24 +010012982 if ((uintptr_t)r > 1)
12983 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012984
Denys Vlasenko73067272010-01-12 22:11:24 +010012985 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012986}
12987
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012988static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020012989umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012990{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012991 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000012992
Eric Andersenc470f442003-07-28 09:56:35 +000012993 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000012994 int symbolic_mode = 0;
12995
12996 while (nextopt("S") != '\0') {
12997 symbolic_mode = 1;
12998 }
12999
Denis Vlasenkob012b102007-02-19 22:43:01 +000013000 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000013001 mask = umask(0);
13002 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000013003 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000013004
Denys Vlasenko6283f982015-10-07 16:56:20 +020013005 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000013006 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013007 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000013008 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013009 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000013010
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013011 i = 2;
13012 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020013013 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000013014 *p++ = permuser[i];
13015 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013016 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020013017 if (!(mask & 0400)) *p++ = 'r';
13018 if (!(mask & 0200)) *p++ = 'w';
13019 if (!(mask & 0100)) *p++ = 'x';
13020 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013021 if (--i < 0)
13022 break;
Eric Andersenc470f442003-07-28 09:56:35 +000013023 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020013024 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020013025 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000013026 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020013027 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013028 }
13029 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013030 char *modestr = *argptr;
13031 /* numeric umasks are taken as-is */
13032 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
13033 if (!isdigit(modestr[0]))
13034 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020013035 mask = bb_parse_mode(modestr, mask);
13036 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020013037 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000013038 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020013039 if (!isdigit(modestr[0]))
13040 mask ^= 0777;
13041 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000013042 }
13043 return 0;
13044}
13045
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020013046static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013047ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000013048{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010013049 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000013050}
13051
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013052/* ============ main() and helpers */
13053
13054/*
13055 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013056 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013057static void
13058exitshell(void)
13059{
13060 struct jmploc loc;
13061 char *p;
13062 int status;
13063
Denys Vlasenkobede2152011-09-04 16:12:33 +020013064#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13065 save_history(line_input_state);
13066#endif
13067
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013068 status = exitstatus;
13069 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13070 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013071 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013072/* dash bug: it just does _exit(exitstatus) here
13073 * but we have to do setjobctl(0) first!
13074 * (bug is still not fixed in dash-0.5.3 - if you run dash
13075 * under Midnight Commander, on exit from dash MC is backgrounded) */
13076 status = exitstatus;
13077 goto out;
13078 }
13079 exception_handler = &loc;
13080 p = trap[0];
13081 if (p) {
13082 trap[0] = NULL;
13083 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020013084 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013085 }
13086 flush_stdout_stderr();
13087 out:
13088 setjobctl(0);
13089 _exit(status);
13090 /* NOTREACHED */
13091}
13092
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013093static void
13094init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013095{
13096 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013097 /* we will never free this */
13098 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013099
13100 /* from trap.c: */
13101 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013102 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13103 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13104 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013105 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013106
13107 /* from var.c: */
13108 {
13109 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013110 const char *p;
13111 struct stat st1, st2;
13112
13113 initvar();
13114 for (envp = environ; envp && *envp; envp++) {
13115 if (strchr(*envp, '=')) {
13116 setvareq(*envp, VEXPORT|VTEXTFIXED);
13117 }
13118 }
13119
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013120 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013121#if ENABLE_ASH_BASH_COMPAT
13122 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013123 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013124 if (!lookupvar("HOSTNAME")) {
13125 struct utsname uts;
13126 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013127 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013128 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013129#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013130 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013131 if (p) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013132 if (p[0] != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013133 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13134 ) {
Denys Vlasenkoef159702016-09-01 11:16:22 +020013135 p = NULL;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013136 }
13137 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013138 setpwd(p, 0);
13139 }
13140}
13141
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013142
13143//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013144//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013145//usage:#define ash_full_usage "\n\n"
13146//usage: "Unix shell interpreter"
13147
13148//usage:#if ENABLE_FEATURE_SH_IS_ASH
13149//usage:# define sh_trivial_usage ash_trivial_usage
13150//usage:# define sh_full_usage ash_full_usage
13151//usage:#endif
13152//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13153//usage:# define bash_trivial_usage ash_trivial_usage
13154//usage:# define bash_full_usage ash_full_usage
13155//usage:#endif
13156
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013157/*
13158 * Process the shell command line arguments.
13159 */
13160static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013161procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013162{
13163 int i;
13164 const char *xminusc;
13165 char **xargv;
13166
13167 xargv = argv;
13168 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013169 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013170 xargv++;
13171 for (i = 0; i < NOPTS; i++)
13172 optlist[i] = 2;
13173 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013174 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013175 /* it already printed err message */
13176 raise_exception(EXERROR);
13177 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013178 xargv = argptr;
13179 xminusc = minusc;
13180 if (*xargv == NULL) {
13181 if (xminusc)
13182 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13183 sflag = 1;
13184 }
13185 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13186 iflag = 1;
13187 if (mflag == 2)
13188 mflag = iflag;
13189 for (i = 0; i < NOPTS; i++)
13190 if (optlist[i] == 2)
13191 optlist[i] = 0;
13192#if DEBUG == 2
13193 debug = 1;
13194#endif
13195 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13196 if (xminusc) {
13197 minusc = *xargv++;
13198 if (*xargv)
13199 goto setarg0;
13200 } else if (!sflag) {
13201 setinputfile(*xargv, 0);
13202 setarg0:
13203 arg0 = *xargv++;
13204 commandname = arg0;
13205 }
13206
13207 shellparam.p = xargv;
13208#if ENABLE_ASH_GETOPTS
13209 shellparam.optind = 1;
13210 shellparam.optoff = -1;
13211#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013212 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013213 while (*xargv) {
13214 shellparam.nparam++;
13215 xargv++;
13216 }
13217 optschanged();
13218}
13219
13220/*
13221 * Read /etc/profile or .profile.
13222 */
13223static void
13224read_profile(const char *name)
13225{
13226 int skip;
13227
13228 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13229 return;
13230 skip = cmdloop(0);
13231 popfile();
13232 if (skip)
13233 exitshell();
13234}
13235
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013236/*
13237 * This routine is called when an error or an interrupt occurs in an
13238 * interactive shell and control is returned to the main command loop.
13239 */
13240static void
13241reset(void)
13242{
13243 /* from eval.c: */
13244 evalskip = 0;
13245 loopnest = 0;
13246 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013247 g_parsefile->left_in_buffer = 0;
13248 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013249 popallfiles();
13250 /* from parser.c: */
13251 tokpushback = 0;
13252 checkkwd = 0;
13253 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013254 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013255}
13256
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013257#if PROFILE
13258static short profile_buf[16384];
13259extern int etext();
13260#endif
13261
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013262/*
13263 * Main routine. We initialize things, parse the arguments, execute
13264 * profiles if we're a login shell, and then call cmdloop to execute
13265 * commands. The setjmp call sets up the location to jump to when an
13266 * exception occurs. When an exception occurs the variable "state"
13267 * is used to figure out how far we had gotten.
13268 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013269int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013270int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013271{
Mike Frysinger98c52642009-04-02 10:02:37 +000013272 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013273 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013274 struct jmploc jmploc;
13275 struct stackmark smark;
13276
Denis Vlasenko01631112007-12-16 17:20:38 +000013277 /* Initialize global data */
13278 INIT_G_misc();
13279 INIT_G_memstack();
13280 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013281#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013282 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013283#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013284 INIT_G_cmdtable();
13285
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013286#if PROFILE
13287 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13288#endif
13289
13290#if ENABLE_FEATURE_EDITING
13291 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13292#endif
13293 state = 0;
13294 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013295 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013296 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013297
13298 reset();
13299
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013300 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013301 if (e == EXERROR)
13302 exitstatus = 2;
13303 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013304 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013305 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013306 }
13307 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013308 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013309 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013310
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013311 popstackmark(&smark);
13312 FORCE_INT_ON; /* enable interrupts */
13313 if (s == 1)
13314 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013315 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013316 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013317 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013318 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013319 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013320 }
13321 exception_handler = &jmploc;
13322#if DEBUG
13323 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013324 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013325 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013326#endif
13327 rootpid = getpid();
13328
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013329 init();
13330 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013331 procargs(argv);
13332
Denys Vlasenko6088e132010-12-25 23:58:42 +010013333 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013334 isloginsh = 1;
13335 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013336 const char *hp;
13337
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013338 state = 1;
13339 read_profile("/etc/profile");
13340 state1:
13341 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013342 hp = lookupvar("HOME");
13343 if (hp) {
13344 hp = concat_path_file(hp, ".profile");
13345 read_profile(hp);
13346 free((char*)hp);
13347 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013348 }
13349 state2:
13350 state = 3;
13351 if (
13352#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013353 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013354#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013355 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013356 ) {
13357 shinit = lookupvar("ENV");
13358 if (shinit != NULL && *shinit != '\0') {
13359 read_profile(shinit);
13360 }
13361 }
13362 state3:
13363 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013364 if (minusc) {
13365 /* evalstring pushes parsefile stack.
13366 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013367 * is one of stacked source fds.
13368 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013369 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013370 // ^^ not necessary since now we special-case fd 0
13371 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013372 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013373 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013374
13375 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013376#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013377 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013378 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013379 if (!hp) {
13380 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013381 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013382 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013383 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013384 free((char*)hp);
13385 hp = lookupvar("HISTFILE");
13386 }
13387 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013388 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013389 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013390# if ENABLE_FEATURE_SH_HISTFILESIZE
13391 hp = lookupvar("HISTFILESIZE");
13392 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13393# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013394 }
13395#endif
13396 state4: /* XXX ??? - why isn't this before the "if" statement */
13397 cmdloop(1);
13398 }
13399#if PROFILE
13400 monitor(0);
13401#endif
13402#ifdef GPROF
13403 {
13404 extern void _mcleanup(void);
13405 _mcleanup();
13406 }
13407#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013408 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013409 exitshell();
13410 /* NOTREACHED */
13411}
13412
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013413
Eric Andersendf82f612001-06-28 07:46:40 +000013414/*-
13415 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013416 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013417 *
13418 * This code is derived from software contributed to Berkeley by
13419 * Kenneth Almquist.
13420 *
13421 * Redistribution and use in source and binary forms, with or without
13422 * modification, are permitted provided that the following conditions
13423 * are met:
13424 * 1. Redistributions of source code must retain the above copyright
13425 * notice, this list of conditions and the following disclaimer.
13426 * 2. Redistributions in binary form must reproduce the above copyright
13427 * notice, this list of conditions and the following disclaimer in the
13428 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013429 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013430 * may be used to endorse or promote products derived from this software
13431 * without specific prior written permission.
13432 *
13433 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13434 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13435 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13436 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13437 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13438 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13439 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13440 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13441 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13442 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13443 * SUCH DAMAGE.
13444 */