blob: 282f761fc94ab645caab881ebbd9ffa762026ee8 [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 <paths.h>
41#include <setjmp.h>
42#include <fnmatch.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) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000327#define S_HARD_IGN 4 /* signal is ignored permenantly */
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
540static void
541outcslow(int c, FILE *dest)
542{
543 INT_OFF;
544 putc(c, dest);
545 fflush(dest);
546 INT_ON;
547}
548
549static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
550static int
551out1fmt(const char *fmt, ...)
552{
553 va_list ap;
554 int r;
555
556 INT_OFF;
557 va_start(ap, fmt);
558 r = vprintf(fmt, ap);
559 va_end(ap);
560 INT_ON;
561 return r;
562}
563
564static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
565static int
566fmtstr(char *outbuf, size_t length, const char *fmt, ...)
567{
568 va_list ap;
569 int ret;
570
571 va_start(ap, fmt);
572 INT_OFF;
573 ret = vsnprintf(outbuf, length, fmt, ap);
574 va_end(ap);
575 INT_ON;
576 return ret;
577}
578
579static void
580out1str(const char *p)
581{
582 outstr(p, stdout);
583}
584
585static void
586out2str(const char *p)
587{
588 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100589 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000590}
591
592
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000593/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000594
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000595/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100596#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200597#define CTLESC ((unsigned char)'\201') /* escape next character */
598#define CTLVAR ((unsigned char)'\202') /* variable defn */
599#define CTLENDVAR ((unsigned char)'\203')
600#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200601#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
602#define CTLENDARI ((unsigned char)'\207')
603#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100604#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000605
606/* variable substitution byte (follows CTLVAR) */
607#define VSTYPE 0x0f /* type of variable substitution */
608#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000609
610/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000611#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
612#define VSMINUS 0x2 /* ${var-text} */
613#define VSPLUS 0x3 /* ${var+text} */
614#define VSQUESTION 0x4 /* ${var?message} */
615#define VSASSIGN 0x5 /* ${var=text} */
616#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
617#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
618#define VSTRIMLEFT 0x8 /* ${var#pattern} */
619#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
620#define VSLENGTH 0xa /* ${#var} */
621#if ENABLE_ASH_BASH_COMPAT
622#define VSSUBSTR 0xc /* ${var:position:length} */
623#define VSREPLACE 0xd /* ${var/pattern/replacement} */
624#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
625#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000626
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000627static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200628 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000629};
Ron Yorston549deab2015-05-18 09:57:51 +0200630#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000631
Denis Vlasenko559691a2008-10-05 18:39:31 +0000632#define NCMD 0
633#define NPIPE 1
634#define NREDIR 2
635#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000636#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000637#define NAND 5
638#define NOR 6
639#define NSEMI 7
640#define NIF 8
641#define NWHILE 9
642#define NUNTIL 10
643#define NFOR 11
644#define NCASE 12
645#define NCLIST 13
646#define NDEFUN 14
647#define NARG 15
648#define NTO 16
649#if ENABLE_ASH_BASH_COMPAT
650#define NTO2 17
651#endif
652#define NCLOBBER 18
653#define NFROM 19
654#define NFROMTO 20
655#define NAPPEND 21
656#define NTOFD 22
657#define NFROMFD 23
658#define NHERE 24
659#define NXHERE 25
660#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000661#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000662
663union node;
664
665struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000666 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000667 union node *assign;
668 union node *args;
669 union node *redirect;
670};
671
672struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000673 smallint type;
674 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000675 struct nodelist *cmdlist;
676};
677
678struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000679 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000680 union node *n;
681 union node *redirect;
682};
683
684struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000685 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000686 union node *ch1;
687 union node *ch2;
688};
689
690struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000691 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000692 union node *test;
693 union node *ifpart;
694 union node *elsepart;
695};
696
697struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000698 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000699 union node *args;
700 union node *body;
701 char *var;
702};
703
704struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000705 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000706 union node *expr;
707 union node *cases;
708};
709
710struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000711 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000712 union node *next;
713 union node *pattern;
714 union node *body;
715};
716
717struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000718 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000719 union node *next;
720 char *text;
721 struct nodelist *backquote;
722};
723
Denis Vlasenko559691a2008-10-05 18:39:31 +0000724/* nfile and ndup layout must match!
725 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
726 * that it is actually NTO2 (>&file), and change its type.
727 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000728struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000729 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000730 union node *next;
731 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000732 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000733 union node *fname;
734 char *expfname;
735};
736
737struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000738 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000739 union node *next;
740 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000741 int dupfd;
742 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000743 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000744};
745
746struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000747 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000748 union node *next;
749 int fd;
750 union node *doc;
751};
752
753struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000754 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000755 union node *com;
756};
757
758union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000759 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000760 struct ncmd ncmd;
761 struct npipe npipe;
762 struct nredir nredir;
763 struct nbinary nbinary;
764 struct nif nif;
765 struct nfor nfor;
766 struct ncase ncase;
767 struct nclist nclist;
768 struct narg narg;
769 struct nfile nfile;
770 struct ndup ndup;
771 struct nhere nhere;
772 struct nnot nnot;
773};
774
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200775/*
776 * NODE_EOF is returned by parsecmd when it encounters an end of file.
777 * It must be distinct from NULL.
778 */
779#define NODE_EOF ((union node *) -1L)
780
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000781struct nodelist {
782 struct nodelist *next;
783 union node *n;
784};
785
786struct funcnode {
787 int count;
788 union node n;
789};
790
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000791/*
792 * Free a parse tree.
793 */
794static void
795freefunc(struct funcnode *f)
796{
797 if (f && --f->count < 0)
798 free(f);
799}
800
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000801
802/* ============ Debugging output */
803
804#if DEBUG
805
806static FILE *tracefile;
807
808static void
809trace_printf(const char *fmt, ...)
810{
811 va_list va;
812
813 if (debug != 1)
814 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000815 if (DEBUG_TIME)
816 fprintf(tracefile, "%u ", (int) time(NULL));
817 if (DEBUG_PID)
818 fprintf(tracefile, "[%u] ", (int) getpid());
819 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200820 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000821 va_start(va, fmt);
822 vfprintf(tracefile, fmt, va);
823 va_end(va);
824}
825
826static void
827trace_vprintf(const char *fmt, va_list va)
828{
829 if (debug != 1)
830 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000831 if (DEBUG_TIME)
832 fprintf(tracefile, "%u ", (int) time(NULL));
833 if (DEBUG_PID)
834 fprintf(tracefile, "[%u] ", (int) getpid());
835 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200836 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000837 vfprintf(tracefile, fmt, va);
838}
839
840static void
841trace_puts(const char *s)
842{
843 if (debug != 1)
844 return;
845 fputs(s, tracefile);
846}
847
848static void
849trace_puts_quoted(char *s)
850{
851 char *p;
852 char c;
853
854 if (debug != 1)
855 return;
856 putc('"', tracefile);
857 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100858 switch ((unsigned char)*p) {
859 case '\n': c = 'n'; goto backslash;
860 case '\t': c = 't'; goto backslash;
861 case '\r': c = 'r'; goto backslash;
862 case '\"': c = '\"'; goto backslash;
863 case '\\': c = '\\'; goto backslash;
864 case CTLESC: c = 'e'; goto backslash;
865 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100866 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000867 backslash:
868 putc('\\', tracefile);
869 putc(c, tracefile);
870 break;
871 default:
872 if (*p >= ' ' && *p <= '~')
873 putc(*p, tracefile);
874 else {
875 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100876 putc((*p >> 6) & 03, tracefile);
877 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000878 putc(*p & 07, tracefile);
879 }
880 break;
881 }
882 }
883 putc('"', tracefile);
884}
885
886static void
887trace_puts_args(char **ap)
888{
889 if (debug != 1)
890 return;
891 if (!*ap)
892 return;
893 while (1) {
894 trace_puts_quoted(*ap);
895 if (!*++ap) {
896 putc('\n', tracefile);
897 break;
898 }
899 putc(' ', tracefile);
900 }
901}
902
903static void
904opentrace(void)
905{
906 char s[100];
907#ifdef O_APPEND
908 int flags;
909#endif
910
911 if (debug != 1) {
912 if (tracefile)
913 fflush(tracefile);
914 /* leave open because libedit might be using it */
915 return;
916 }
917 strcpy(s, "./trace");
918 if (tracefile) {
919 if (!freopen(s, "a", tracefile)) {
920 fprintf(stderr, "Can't re-open %s\n", s);
921 debug = 0;
922 return;
923 }
924 } else {
925 tracefile = fopen(s, "a");
926 if (tracefile == NULL) {
927 fprintf(stderr, "Can't open %s\n", s);
928 debug = 0;
929 return;
930 }
931 }
932#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000933 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000934 if (flags >= 0)
935 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
936#endif
937 setlinebuf(tracefile);
938 fputs("\nTracing started.\n", tracefile);
939}
940
941static void
942indent(int amount, char *pfx, FILE *fp)
943{
944 int i;
945
946 for (i = 0; i < amount; i++) {
947 if (pfx && i == amount - 1)
948 fputs(pfx, fp);
949 putc('\t', fp);
950 }
951}
952
953/* little circular references here... */
954static void shtree(union node *n, int ind, char *pfx, FILE *fp);
955
956static void
957sharg(union node *arg, FILE *fp)
958{
959 char *p;
960 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100961 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000962
963 if (arg->type != NARG) {
964 out1fmt("<node type %d>\n", arg->type);
965 abort();
966 }
967 bqlist = arg->narg.backquote;
968 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100969 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000970 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700971 p++;
972 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000973 break;
974 case CTLVAR:
975 putc('$', fp);
976 putc('{', fp);
977 subtype = *++p;
978 if (subtype == VSLENGTH)
979 putc('#', fp);
980
Dan Fandrich77d48722010-09-07 23:38:28 -0700981 while (*p != '=') {
982 putc(*p, fp);
983 p++;
984 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000985
986 if (subtype & VSNUL)
987 putc(':', fp);
988
989 switch (subtype & VSTYPE) {
990 case VSNORMAL:
991 putc('}', fp);
992 break;
993 case VSMINUS:
994 putc('-', fp);
995 break;
996 case VSPLUS:
997 putc('+', fp);
998 break;
999 case VSQUESTION:
1000 putc('?', fp);
1001 break;
1002 case VSASSIGN:
1003 putc('=', fp);
1004 break;
1005 case VSTRIMLEFT:
1006 putc('#', fp);
1007 break;
1008 case VSTRIMLEFTMAX:
1009 putc('#', fp);
1010 putc('#', fp);
1011 break;
1012 case VSTRIMRIGHT:
1013 putc('%', fp);
1014 break;
1015 case VSTRIMRIGHTMAX:
1016 putc('%', fp);
1017 putc('%', fp);
1018 break;
1019 case VSLENGTH:
1020 break;
1021 default:
1022 out1fmt("<subtype %d>", subtype);
1023 }
1024 break;
1025 case CTLENDVAR:
1026 putc('}', fp);
1027 break;
1028 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001029 putc('$', fp);
1030 putc('(', fp);
1031 shtree(bqlist->n, -1, NULL, fp);
1032 putc(')', fp);
1033 break;
1034 default:
1035 putc(*p, fp);
1036 break;
1037 }
1038 }
1039}
1040
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001041static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001042shcmd(union node *cmd, FILE *fp)
1043{
1044 union node *np;
1045 int first;
1046 const char *s;
1047 int dftfd;
1048
1049 first = 1;
1050 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001051 if (!first)
1052 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001053 sharg(np, fp);
1054 first = 0;
1055 }
1056 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001057 if (!first)
1058 putc(' ', fp);
1059 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001060 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001061 case NTO: s = ">>"+1; dftfd = 1; break;
1062 case NCLOBBER: s = ">|"; dftfd = 1; break;
1063 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001064#if ENABLE_ASH_BASH_COMPAT
1065 case NTO2:
1066#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001067 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001068 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001069 case NFROMFD: s = "<&"; break;
1070 case NFROMTO: s = "<>"; break;
1071 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001072 }
1073 if (np->nfile.fd != dftfd)
1074 fprintf(fp, "%d", np->nfile.fd);
1075 fputs(s, fp);
1076 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1077 fprintf(fp, "%d", np->ndup.dupfd);
1078 } else {
1079 sharg(np->nfile.fname, fp);
1080 }
1081 first = 0;
1082 }
1083}
1084
1085static void
1086shtree(union node *n, int ind, char *pfx, FILE *fp)
1087{
1088 struct nodelist *lp;
1089 const char *s;
1090
1091 if (n == NULL)
1092 return;
1093
1094 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001095
1096 if (n == NODE_EOF) {
1097 fputs("<EOF>", fp);
1098 return;
1099 }
1100
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001101 switch (n->type) {
1102 case NSEMI:
1103 s = "; ";
1104 goto binop;
1105 case NAND:
1106 s = " && ";
1107 goto binop;
1108 case NOR:
1109 s = " || ";
1110 binop:
1111 shtree(n->nbinary.ch1, ind, NULL, fp);
1112 /* if (ind < 0) */
1113 fputs(s, fp);
1114 shtree(n->nbinary.ch2, ind, NULL, fp);
1115 break;
1116 case NCMD:
1117 shcmd(n, fp);
1118 if (ind >= 0)
1119 putc('\n', fp);
1120 break;
1121 case NPIPE:
1122 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001123 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001124 if (lp->next)
1125 fputs(" | ", fp);
1126 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001127 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001128 fputs(" &", fp);
1129 if (ind >= 0)
1130 putc('\n', fp);
1131 break;
1132 default:
1133 fprintf(fp, "<node type %d>", n->type);
1134 if (ind >= 0)
1135 putc('\n', fp);
1136 break;
1137 }
1138}
1139
1140static void
1141showtree(union node *n)
1142{
1143 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001144 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001145}
1146
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001147#endif /* DEBUG */
1148
1149
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001150/* ============ Parser data */
1151
1152/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001153 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1154 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001155struct strlist {
1156 struct strlist *next;
1157 char *text;
1158};
1159
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001160struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001161
Denis Vlasenkob012b102007-02-19 22:43:01 +00001162struct strpush {
1163 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001164 char *prev_string;
1165 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001166#if ENABLE_ASH_ALIAS
1167 struct alias *ap; /* if push was associated with an alias */
1168#endif
1169 char *string; /* remember the string since it may change */
1170};
1171
1172struct parsefile {
1173 struct parsefile *prev; /* preceding file on stack */
1174 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001175 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001176 int left_in_line; /* number of chars left in this line */
1177 int left_in_buffer; /* number of chars left in this buffer past the line */
1178 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001179 char *buf; /* input buffer */
1180 struct strpush *strpush; /* for pushing strings at this level */
1181 struct strpush basestrpush; /* so pushing one is fast */
1182};
1183
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001184static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001185static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001186static int startlinno; /* line # where last token started */
1187static char *commandname; /* currently executing command */
1188static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001189static uint8_t exitstatus; /* exit status of last command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001190
1191
1192/* ============ Message printing */
1193
1194static void
1195ash_vmsg(const char *msg, va_list ap)
1196{
1197 fprintf(stderr, "%s: ", arg0);
1198 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001199 if (strcmp(arg0, commandname))
1200 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001201 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001202 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001203 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001204 vfprintf(stderr, msg, ap);
1205 outcslow('\n', stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001206}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001207
1208/*
1209 * Exverror is called to raise the error exception. If the second argument
1210 * is not NULL then error prints an error message using printf style
1211 * formatting. It then raises the error exception.
1212 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001213static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001214static void
1215ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001216{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001217#if DEBUG
1218 if (msg) {
1219 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1220 TRACEV((msg, ap));
1221 TRACE(("\") pid=%d\n", getpid()));
1222 } else
1223 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1224 if (msg)
1225#endif
1226 ash_vmsg(msg, ap);
1227
1228 flush_stdout_stderr();
1229 raise_exception(cond);
1230 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001231}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001232
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001233static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001234static void
1235ash_msg_and_raise_error(const char *msg, ...)
1236{
1237 va_list ap;
1238
1239 va_start(ap, msg);
1240 ash_vmsg_and_raise(EXERROR, msg, ap);
1241 /* NOTREACHED */
1242 va_end(ap);
1243}
1244
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001245static void raise_error_syntax(const char *) NORETURN;
1246static void
1247raise_error_syntax(const char *msg)
1248{
1249 ash_msg_and_raise_error("syntax error: %s", msg);
1250 /* NOTREACHED */
1251}
1252
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001253static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001254static void
1255ash_msg_and_raise(int cond, const char *msg, ...)
1256{
1257 va_list ap;
1258
1259 va_start(ap, msg);
1260 ash_vmsg_and_raise(cond, msg, ap);
1261 /* NOTREACHED */
1262 va_end(ap);
1263}
1264
1265/*
1266 * error/warning routines for external builtins
1267 */
1268static void
1269ash_msg(const char *fmt, ...)
1270{
1271 va_list ap;
1272
1273 va_start(ap, fmt);
1274 ash_vmsg(fmt, ap);
1275 va_end(ap);
1276}
1277
1278/*
1279 * Return a string describing an error. The returned string may be a
1280 * pointer to a static buffer that will be overwritten on the next call.
1281 * Action describes the operation that got the error.
1282 */
1283static const char *
1284errmsg(int e, const char *em)
1285{
1286 if (e == ENOENT || e == ENOTDIR) {
1287 return em;
1288 }
1289 return strerror(e);
1290}
1291
1292
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001293/* ============ Memory allocation */
1294
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001295#if 0
1296/* I consider these wrappers nearly useless:
1297 * ok, they return you to nearest exception handler, but
1298 * how much memory do you leak in the process, making
1299 * memory starvation worse?
1300 */
1301static void *
1302ckrealloc(void * p, size_t nbytes)
1303{
1304 p = realloc(p, nbytes);
1305 if (!p)
1306 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1307 return p;
1308}
1309
1310static void *
1311ckmalloc(size_t nbytes)
1312{
1313 return ckrealloc(NULL, nbytes);
1314}
1315
1316static void *
1317ckzalloc(size_t nbytes)
1318{
1319 return memset(ckmalloc(nbytes), 0, nbytes);
1320}
1321
1322static char *
1323ckstrdup(const char *s)
1324{
1325 char *p = strdup(s);
1326 if (!p)
1327 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1328 return p;
1329}
1330#else
1331/* Using bbox equivalents. They exit if out of memory */
1332# define ckrealloc xrealloc
1333# define ckmalloc xmalloc
1334# define ckzalloc xzalloc
1335# define ckstrdup xstrdup
1336#endif
1337
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001338/*
1339 * It appears that grabstackstr() will barf with such alignments
1340 * because stalloc() will return a string allocated in a new stackblock.
1341 */
1342#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1343enum {
1344 /* Most machines require the value returned from malloc to be aligned
1345 * in some way. The following macro will get this right
1346 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001347 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001348 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001349 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001350};
1351
1352struct stack_block {
1353 struct stack_block *prev;
1354 char space[MINSIZE];
1355};
1356
1357struct stackmark {
1358 struct stack_block *stackp;
1359 char *stacknxt;
1360 size_t stacknleft;
1361 struct stackmark *marknext;
1362};
1363
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001364
Denis Vlasenko01631112007-12-16 17:20:38 +00001365struct globals_memstack {
1366 struct stack_block *g_stackp; // = &stackbase;
1367 struct stackmark *markp;
1368 char *g_stacknxt; // = stackbase.space;
1369 char *sstrend; // = stackbase.space + MINSIZE;
1370 size_t g_stacknleft; // = MINSIZE;
1371 int herefd; // = -1;
1372 struct stack_block stackbase;
1373};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001374extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1375#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001376#define g_stackp (G_memstack.g_stackp )
1377#define markp (G_memstack.markp )
1378#define g_stacknxt (G_memstack.g_stacknxt )
1379#define sstrend (G_memstack.sstrend )
1380#define g_stacknleft (G_memstack.g_stacknleft)
1381#define herefd (G_memstack.herefd )
1382#define stackbase (G_memstack.stackbase )
1383#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001384 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1385 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001386 g_stackp = &stackbase; \
1387 g_stacknxt = stackbase.space; \
1388 g_stacknleft = MINSIZE; \
1389 sstrend = stackbase.space + MINSIZE; \
1390 herefd = -1; \
1391} while (0)
1392
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001393
Denis Vlasenko01631112007-12-16 17:20:38 +00001394#define stackblock() ((void *)g_stacknxt)
1395#define stackblocksize() g_stacknleft
1396
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001397/*
1398 * Parse trees for commands are allocated in lifo order, so we use a stack
1399 * to make this more efficient, and also to avoid all sorts of exception
1400 * handling code to handle interrupts in the middle of a parse.
1401 *
1402 * The size 504 was chosen because the Ultrix malloc handles that size
1403 * well.
1404 */
1405static void *
1406stalloc(size_t nbytes)
1407{
1408 char *p;
1409 size_t aligned;
1410
1411 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001412 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001413 size_t len;
1414 size_t blocksize;
1415 struct stack_block *sp;
1416
1417 blocksize = aligned;
1418 if (blocksize < MINSIZE)
1419 blocksize = MINSIZE;
1420 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1421 if (len < blocksize)
1422 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1423 INT_OFF;
1424 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001425 sp->prev = g_stackp;
1426 g_stacknxt = sp->space;
1427 g_stacknleft = blocksize;
1428 sstrend = g_stacknxt + blocksize;
1429 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001430 INT_ON;
1431 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001432 p = g_stacknxt;
1433 g_stacknxt += aligned;
1434 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001435 return p;
1436}
1437
Denis Vlasenko597906c2008-02-20 16:38:54 +00001438static void *
1439stzalloc(size_t nbytes)
1440{
1441 return memset(stalloc(nbytes), 0, nbytes);
1442}
1443
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001444static void
1445stunalloc(void *p)
1446{
1447#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001448 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001449 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001450 abort();
1451 }
1452#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001453 g_stacknleft += g_stacknxt - (char *)p;
1454 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001455}
1456
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001457/*
1458 * Like strdup but works with the ash stack.
1459 */
1460static char *
1461ststrdup(const char *p)
1462{
1463 size_t len = strlen(p) + 1;
1464 return memcpy(stalloc(len), p, len);
1465}
1466
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001467static void
1468setstackmark(struct stackmark *mark)
1469{
Denis Vlasenko01631112007-12-16 17:20:38 +00001470 mark->stackp = g_stackp;
1471 mark->stacknxt = g_stacknxt;
1472 mark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001473 mark->marknext = markp;
1474 markp = mark;
1475}
1476
1477static void
1478popstackmark(struct stackmark *mark)
1479{
1480 struct stack_block *sp;
1481
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001482 if (!mark->stackp)
1483 return;
1484
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001485 INT_OFF;
1486 markp = mark->marknext;
Denis Vlasenko01631112007-12-16 17:20:38 +00001487 while (g_stackp != mark->stackp) {
1488 sp = g_stackp;
1489 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001490 free(sp);
1491 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001492 g_stacknxt = mark->stacknxt;
1493 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001494 sstrend = mark->stacknxt + mark->stacknleft;
1495 INT_ON;
1496}
1497
1498/*
1499 * When the parser reads in a string, it wants to stick the string on the
1500 * stack and only adjust the stack pointer when it knows how big the
1501 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1502 * of space on top of the stack and stackblocklen returns the length of
1503 * this block. Growstackblock will grow this space by at least one byte,
1504 * possibly moving it (like realloc). Grabstackblock actually allocates the
1505 * part of the block that has been used.
1506 */
1507static void
1508growstackblock(void)
1509{
1510 size_t newlen;
1511
Denis Vlasenko01631112007-12-16 17:20:38 +00001512 newlen = g_stacknleft * 2;
1513 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001514 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1515 if (newlen < 128)
1516 newlen += 128;
1517
Denis Vlasenko01631112007-12-16 17:20:38 +00001518 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001519 struct stack_block *oldstackp;
1520 struct stackmark *xmark;
1521 struct stack_block *sp;
1522 struct stack_block *prevstackp;
1523 size_t grosslen;
1524
1525 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001526 oldstackp = g_stackp;
1527 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001528 prevstackp = sp->prev;
1529 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1530 sp = ckrealloc(sp, grosslen);
1531 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001532 g_stackp = sp;
1533 g_stacknxt = sp->space;
1534 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001535 sstrend = sp->space + newlen;
1536
1537 /*
1538 * Stack marks pointing to the start of the old block
1539 * must be relocated to point to the new block
1540 */
1541 xmark = markp;
1542 while (xmark != NULL && xmark->stackp == oldstackp) {
Denis Vlasenko01631112007-12-16 17:20:38 +00001543 xmark->stackp = g_stackp;
1544 xmark->stacknxt = g_stacknxt;
1545 xmark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001546 xmark = xmark->marknext;
1547 }
1548 INT_ON;
1549 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001550 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001551 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001552 char *p = stalloc(newlen);
1553
1554 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001555 g_stacknxt = memcpy(p, oldspace, oldlen);
1556 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001557 }
1558}
1559
1560static void
1561grabstackblock(size_t len)
1562{
1563 len = SHELL_ALIGN(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001564 g_stacknxt += len;
1565 g_stacknleft -= len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001566}
1567
1568/*
1569 * The following routines are somewhat easier to use than the above.
1570 * The user declares a variable of type STACKSTR, which may be declared
1571 * to be a register. The macro STARTSTACKSTR initializes things. Then
1572 * the user uses the macro STPUTC to add characters to the string. In
1573 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1574 * grown as necessary. When the user is done, she can just leave the
1575 * string there and refer to it using stackblock(). Or she can allocate
1576 * the space for it using grabstackstr(). If it is necessary to allow
1577 * someone else to use the stack temporarily and then continue to grow
1578 * the string, the user should use grabstack to allocate the space, and
1579 * then call ungrabstr(p) to return to the previous mode of operation.
1580 *
1581 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1582 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1583 * is space for at least one character.
1584 */
1585static void *
1586growstackstr(void)
1587{
1588 size_t len = stackblocksize();
1589 if (herefd >= 0 && len >= 1024) {
1590 full_write(herefd, stackblock(), len);
1591 return stackblock();
1592 }
1593 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001594 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001595}
1596
1597/*
1598 * Called from CHECKSTRSPACE.
1599 */
1600static char *
1601makestrspace(size_t newlen, char *p)
1602{
Denis Vlasenko01631112007-12-16 17:20:38 +00001603 size_t len = p - g_stacknxt;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001604 size_t size = stackblocksize();
1605
1606 for (;;) {
1607 size_t nleft;
1608
1609 size = stackblocksize();
1610 nleft = size - len;
1611 if (nleft >= newlen)
1612 break;
1613 growstackblock();
1614 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001615 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001616}
1617
1618static char *
1619stack_nputstr(const char *s, size_t n, char *p)
1620{
1621 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001622 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001623 return p;
1624}
1625
1626static char *
1627stack_putstr(const char *s, char *p)
1628{
1629 return stack_nputstr(s, strlen(s), p);
1630}
1631
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001632static char *
1633_STPUTC(int c, char *p)
1634{
1635 if (p == sstrend)
1636 p = growstackstr();
1637 *p++ = c;
1638 return p;
1639}
1640
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001641#define STARTSTACKSTR(p) ((p) = stackblock())
1642#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001643#define CHECKSTRSPACE(n, p) do { \
1644 char *q = (p); \
1645 size_t l = (n); \
1646 size_t m = sstrend - q; \
1647 if (l > m) \
1648 (p) = makestrspace(l, q); \
1649} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001650#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001651#define STACKSTRNUL(p) do { \
1652 if ((p) == sstrend) \
1653 (p) = growstackstr(); \
1654 *(p) = '\0'; \
1655} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001656#define STUNPUTC(p) (--(p))
1657#define STTOPC(p) ((p)[-1])
1658#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001659
1660#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001661#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001662#define stackstrend() ((void *)sstrend)
1663
1664
1665/* ============ String helpers */
1666
1667/*
1668 * prefix -- see if pfx is a prefix of string.
1669 */
1670static char *
1671prefix(const char *string, const char *pfx)
1672{
1673 while (*pfx) {
1674 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001675 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001676 }
1677 return (char *) string;
1678}
1679
1680/*
1681 * Check for a valid number. This should be elsewhere.
1682 */
1683static int
1684is_number(const char *p)
1685{
1686 do {
1687 if (!isdigit(*p))
1688 return 0;
1689 } while (*++p != '\0');
1690 return 1;
1691}
1692
1693/*
1694 * Convert a string of digits to an integer, printing an error message on
1695 * failure.
1696 */
1697static int
1698number(const char *s)
1699{
1700 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001701 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001702 return atoi(s);
1703}
1704
1705/*
1706 * Produce a possibly single quoted string suitable as input to the shell.
1707 * The return string is allocated on the stack.
1708 */
1709static char *
1710single_quote(const char *s)
1711{
1712 char *p;
1713
1714 STARTSTACKSTR(p);
1715
1716 do {
1717 char *q;
1718 size_t len;
1719
1720 len = strchrnul(s, '\'') - s;
1721
1722 q = p = makestrspace(len + 3, p);
1723
1724 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001725 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001726 *q++ = '\'';
1727 s += len;
1728
1729 STADJUST(q - p, p);
1730
Denys Vlasenkocd716832009-11-28 22:14:02 +01001731 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001732 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001733 len = 0;
1734 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001735
1736 q = p = makestrspace(len + 3, p);
1737
1738 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001739 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001740 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001741
1742 STADJUST(q - p, p);
1743 } while (*s);
1744
Denys Vlasenkocd716832009-11-28 22:14:02 +01001745 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001746
1747 return stackblock();
1748}
1749
1750
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001751/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001752
1753static char **argptr; /* argument list for builtin commands */
1754static char *optionarg; /* set by nextopt (like getopt) */
1755static char *optptr; /* used by nextopt */
1756
1757/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001758 * XXX - should get rid of. Have all builtins use getopt(3).
1759 * The library getopt must have the BSD extension static variable
1760 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001761 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001762 * Standard option processing (a la getopt) for builtin routines.
1763 * The only argument that is passed to nextopt is the option string;
1764 * the other arguments are unnecessary. It returns the character,
1765 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001766 */
1767static int
1768nextopt(const char *optstring)
1769{
1770 char *p;
1771 const char *q;
1772 char c;
1773
1774 p = optptr;
1775 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001776 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001777 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001778 if (p == NULL)
1779 return '\0';
1780 if (*p != '-')
1781 return '\0';
1782 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001783 return '\0';
1784 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001785 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001786 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001787 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001788 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001789 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001790 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001791 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001792 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001793 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001794 if (*++q == ':')
1795 q++;
1796 }
1797 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001798 if (*p == '\0') {
1799 p = *argptr++;
1800 if (p == NULL)
1801 ash_msg_and_raise_error("no arg for -%c option", c);
1802 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001803 optionarg = p;
1804 p = NULL;
1805 }
1806 optptr = p;
1807 return c;
1808}
1809
1810
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001811/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001812
Denis Vlasenko01631112007-12-16 17:20:38 +00001813/*
1814 * The parsefile structure pointed to by the global variable parsefile
1815 * contains information about the current file being read.
1816 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001817struct shparam {
1818 int nparam; /* # of positional parameters (without $0) */
1819#if ENABLE_ASH_GETOPTS
1820 int optind; /* next parameter to be processed by getopts */
1821 int optoff; /* used by getopts */
1822#endif
1823 unsigned char malloced; /* if parameter list dynamically allocated */
1824 char **p; /* parameter list */
1825};
1826
1827/*
1828 * Free the list of positional parameters.
1829 */
1830static void
1831freeparam(volatile struct shparam *param)
1832{
Denis Vlasenko01631112007-12-16 17:20:38 +00001833 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001834 char **ap, **ap1;
1835 ap = ap1 = param->p;
1836 while (*ap)
1837 free(*ap++);
1838 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001839 }
1840}
1841
1842#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001843static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001844#endif
1845
1846struct var {
1847 struct var *next; /* next entry in hash list */
1848 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001849 const char *var_text; /* name=value */
1850 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001851 /* the variable gets set/unset */
1852};
1853
1854struct localvar {
1855 struct localvar *next; /* next local variable in list */
1856 struct var *vp; /* the variable that was made local */
1857 int flags; /* saved flags */
1858 const char *text; /* saved text */
1859};
1860
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001861/* flags */
1862#define VEXPORT 0x01 /* variable is exported */
1863#define VREADONLY 0x02 /* variable cannot be modified */
1864#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1865#define VTEXTFIXED 0x08 /* text is statically allocated */
1866#define VSTACK 0x10 /* text is allocated on the stack */
1867#define VUNSET 0x20 /* the variable is not set */
1868#define VNOFUNC 0x40 /* don't call the callback function */
1869#define VNOSET 0x80 /* do not set variable - just readonly test */
1870#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001871#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001872# define VDYNAMIC 0x200 /* dynamic variable */
1873#else
1874# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001875#endif
1876
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001877
Denis Vlasenko01631112007-12-16 17:20:38 +00001878/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001879#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001880static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001881change_lc_all(const char *value)
1882{
1883 if (value && *value != '\0')
1884 setlocale(LC_ALL, value);
1885}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001886static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001887change_lc_ctype(const char *value)
1888{
1889 if (value && *value != '\0')
1890 setlocale(LC_CTYPE, value);
1891}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001892#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001893#if ENABLE_ASH_MAIL
1894static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001895static void changemail(const char *var_value) FAST_FUNC;
1896#else
1897# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001898#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001899static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001900#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001901static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001902#endif
1903
Denis Vlasenko01631112007-12-16 17:20:38 +00001904static const struct {
1905 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001906 const char *var_text;
1907 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001908} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001909 /*
1910 * Note: VEXPORT would not work correctly here for NOFORK applets:
1911 * some environment strings may be constant.
1912 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001913 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001914#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001915 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1916 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001917#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001918 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1919 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1920 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1921 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001922#if ENABLE_ASH_GETOPTS
Denis Vlasenko01631112007-12-16 17:20:38 +00001923 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001924#endif
1925#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001926 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001927#endif
1928#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001929 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1930 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001931#endif
1932#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001933 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001934#endif
1935};
1936
Denis Vlasenko0b769642008-07-24 07:54:57 +00001937struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001938
1939struct globals_var {
1940 struct shparam shellparam; /* $@ current positional parameters */
1941 struct redirtab *redirlist;
1942 int g_nullredirs;
1943 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1944 struct var *vartab[VTABSIZE];
1945 struct var varinit[ARRAY_SIZE(varinit_data)];
1946};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001947extern struct globals_var *const ash_ptr_to_globals_var;
1948#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001949#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001950//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001951#define g_nullredirs (G_var.g_nullredirs )
1952#define preverrout_fd (G_var.preverrout_fd)
1953#define vartab (G_var.vartab )
1954#define varinit (G_var.varinit )
1955#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001956 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001957 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1958 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001959 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001960 varinit[i].flags = varinit_data[i].flags; \
1961 varinit[i].var_text = varinit_data[i].var_text; \
1962 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001963 } \
1964} while (0)
1965
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001966#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001967#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001968# define vmail (&vifs)[1]
1969# define vmpath (&vmail)[1]
1970# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001971#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001972# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001973#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001974#define vps1 (&vpath)[1]
1975#define vps2 (&vps1)[1]
1976#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001977#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001978# define voptind (&vps4)[1]
1979# if ENABLE_ASH_RANDOM_SUPPORT
1980# define vrandom (&voptind)[1]
1981# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001982#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001983# if ENABLE_ASH_RANDOM_SUPPORT
1984# define vrandom (&vps4)[1]
1985# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001986#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001987
1988/*
1989 * The following macros access the values of the above variables.
1990 * They have to skip over the name. They return the null string
1991 * for unset variables.
1992 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001993#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001994#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001995#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001996# define mailval() (vmail.var_text + 5)
1997# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001998# define mpathset() ((vmpath.flags & VUNSET) == 0)
1999#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002000#define pathval() (vpath.var_text + 5)
2001#define ps1val() (vps1.var_text + 4)
2002#define ps2val() (vps2.var_text + 4)
2003#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002004#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002005# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002006#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002007
Denis Vlasenko01631112007-12-16 17:20:38 +00002008#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002009static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002010getoptsreset(const char *value)
2011{
2012 shellparam.optind = number(value);
2013 shellparam.optoff = -1;
2014}
2015#endif
2016
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002017/*
2018 * Compares two strings up to the first = or '\0'. The first
2019 * string must be terminated by '='; the second may be terminated by
2020 * either '=' or '\0'.
2021 */
2022static int
2023varcmp(const char *p, const char *q)
2024{
2025 int c, d;
2026
2027 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002028 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002029 goto out;
2030 p++;
2031 q++;
2032 }
2033 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002034 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002035 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002036 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002037 out:
2038 return c - d;
2039}
2040
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002041/*
2042 * Find the appropriate entry in the hash table from the name.
2043 */
2044static struct var **
2045hashvar(const char *p)
2046{
2047 unsigned hashval;
2048
2049 hashval = ((unsigned char) *p) << 4;
2050 while (*p && *p != '=')
2051 hashval += (unsigned char) *p++;
2052 return &vartab[hashval % VTABSIZE];
2053}
2054
2055static int
2056vpcmp(const void *a, const void *b)
2057{
2058 return varcmp(*(const char **)a, *(const char **)b);
2059}
2060
2061/*
2062 * This routine initializes the builtin variables.
2063 */
2064static void
2065initvar(void)
2066{
2067 struct var *vp;
2068 struct var *end;
2069 struct var **vpp;
2070
2071 /*
2072 * PS1 depends on uid
2073 */
2074#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002075 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002076#else
2077 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002078 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002079#endif
2080 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002081 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002082 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002083 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002084 vp->next = *vpp;
2085 *vpp = vp;
2086 } while (++vp < end);
2087}
2088
2089static struct var **
2090findvar(struct var **vpp, const char *name)
2091{
2092 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002093 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002094 break;
2095 }
2096 }
2097 return vpp;
2098}
2099
2100/*
2101 * Find the value of a variable. Returns NULL if not set.
2102 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002103static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002104lookupvar(const char *name)
2105{
2106 struct var *v;
2107
2108 v = *findvar(hashvar(name), name);
2109 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002110#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002111 /*
2112 * Dynamic variables are implemented roughly the same way they are
2113 * in bash. Namely, they're "special" so long as they aren't unset.
2114 * As soon as they're unset, they're no longer dynamic, and dynamic
2115 * lookup will no longer happen at that point. -- PFM.
2116 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002117 if (v->flags & VDYNAMIC)
2118 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002119#endif
2120 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002121 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002122 }
2123 return NULL;
2124}
2125
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002126static void reinit_unicode_for_ash(void)
2127{
2128 /* Unicode support should be activated even if LANG is set
2129 * _during_ shell execution, not only if it was set when
2130 * shell was started. Therefore, re-check LANG every time:
2131 */
2132 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2133 || ENABLE_UNICODE_USING_LOCALE
2134 ) {
2135 const char *s = lookupvar("LC_ALL");
2136 if (!s) s = lookupvar("LC_CTYPE");
2137 if (!s) s = lookupvar("LANG");
2138 reinit_unicode(s);
2139 }
2140}
2141
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002142/*
2143 * Search the environment of a builtin command.
2144 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002145static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002146bltinlookup(const char *name)
2147{
2148 struct strlist *sp;
2149
2150 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002151 if (varcmp(sp->text, name) == 0)
2152 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002153 }
2154 return lookupvar(name);
2155}
2156
2157/*
2158 * Same as setvar except that the variable and value are passed in
2159 * the first argument as name=value. Since the first argument will
2160 * be actually stored in the table, it should not be a string that
2161 * will go away.
2162 * Called with interrupts off.
2163 */
2164static void
2165setvareq(char *s, int flags)
2166{
2167 struct var *vp, **vpp;
2168
2169 vpp = hashvar(s);
2170 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2171 vp = *findvar(vpp, s);
2172 if (vp) {
2173 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2174 const char *n;
2175
2176 if (flags & VNOSAVE)
2177 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002178 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002179 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2180 }
2181
2182 if (flags & VNOSET)
2183 return;
2184
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002185 if (vp->var_func && !(flags & VNOFUNC))
2186 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002187
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002188 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2189 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002190
2191 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2192 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002193 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002194 if (flags & VNOSET)
2195 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002196 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002197 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002198 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002199 *vpp = vp;
2200 }
2201 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2202 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002203 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002204 vp->flags = flags;
2205}
2206
2207/*
2208 * Set the value of a variable. The flags argument is ored with the
2209 * flags of the variable. If val is NULL, the variable is unset.
2210 */
2211static void
2212setvar(const char *name, const char *val, int flags)
2213{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002214 const char *q;
2215 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002216 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002217 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002218 size_t vallen;
2219
2220 q = endofname(name);
2221 p = strchrnul(q, '=');
2222 namelen = p - name;
2223 if (!namelen || p != q)
2224 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2225 vallen = 0;
2226 if (val == NULL) {
2227 flags |= VUNSET;
2228 } else {
2229 vallen = strlen(val);
2230 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002231
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002232 INT_OFF;
2233 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002234 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002235 if (val) {
2236 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002237 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002238 }
2239 *p = '\0';
2240 setvareq(nameeq, flags | VNOSAVE);
2241 INT_ON;
2242}
2243
Denys Vlasenko03dad222010-01-12 23:29:57 +01002244static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002245setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002246{
2247 setvar(name, val, 0);
2248}
2249
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002250#if ENABLE_ASH_GETOPTS
2251/*
2252 * Safe version of setvar, returns 1 on success 0 on failure.
2253 */
2254static int
2255setvarsafe(const char *name, const char *val, int flags)
2256{
2257 int err;
2258 volatile int saveint;
2259 struct jmploc *volatile savehandler = exception_handler;
2260 struct jmploc jmploc;
2261
2262 SAVE_INT(saveint);
2263 if (setjmp(jmploc.loc))
2264 err = 1;
2265 else {
2266 exception_handler = &jmploc;
2267 setvar(name, val, flags);
2268 err = 0;
2269 }
2270 exception_handler = savehandler;
2271 RESTORE_INT(saveint);
2272 return err;
2273}
2274#endif
2275
2276/*
2277 * Unset the specified variable.
2278 */
2279static int
2280unsetvar(const char *s)
2281{
2282 struct var **vpp;
2283 struct var *vp;
2284 int retval;
2285
2286 vpp = findvar(hashvar(s), s);
2287 vp = *vpp;
2288 retval = 2;
2289 if (vp) {
2290 int flags = vp->flags;
2291
2292 retval = 1;
2293 if (flags & VREADONLY)
2294 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002295#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002296 vp->flags &= ~VDYNAMIC;
2297#endif
2298 if (flags & VUNSET)
2299 goto ok;
2300 if ((flags & VSTRFIXED) == 0) {
2301 INT_OFF;
2302 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002303 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002304 *vpp = vp->next;
2305 free(vp);
2306 INT_ON;
2307 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002308 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002309 vp->flags &= ~VEXPORT;
2310 }
2311 ok:
2312 retval = 0;
2313 }
2314 out:
2315 return retval;
2316}
2317
2318/*
2319 * Process a linked list of variable assignments.
2320 */
2321static void
2322listsetvar(struct strlist *list_set_var, int flags)
2323{
2324 struct strlist *lp = list_set_var;
2325
2326 if (!lp)
2327 return;
2328 INT_OFF;
2329 do {
2330 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002331 lp = lp->next;
2332 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002333 INT_ON;
2334}
2335
2336/*
2337 * Generate a list of variables satisfying the given conditions.
2338 */
2339static char **
2340listvars(int on, int off, char ***end)
2341{
2342 struct var **vpp;
2343 struct var *vp;
2344 char **ep;
2345 int mask;
2346
2347 STARTSTACKSTR(ep);
2348 vpp = vartab;
2349 mask = on | off;
2350 do {
2351 for (vp = *vpp; vp; vp = vp->next) {
2352 if ((vp->flags & mask) == on) {
2353 if (ep == stackstrend())
2354 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002355 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002356 }
2357 }
2358 } while (++vpp < vartab + VTABSIZE);
2359 if (ep == stackstrend())
2360 ep = growstackstr();
2361 if (end)
2362 *end = ep;
2363 *ep++ = NULL;
2364 return grabstackstr(ep);
2365}
2366
2367
2368/* ============ Path search helper
2369 *
2370 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002371 * of the path before the first call; path_advance will update
2372 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002373 * the possible path expansions in sequence. If an option (indicated by
2374 * a percent sign) appears in the path entry then the global variable
2375 * pathopt will be set to point to it; otherwise pathopt will be set to
2376 * NULL.
2377 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002378static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002379
2380static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002381path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002382{
2383 const char *p;
2384 char *q;
2385 const char *start;
2386 size_t len;
2387
2388 if (*path == NULL)
2389 return NULL;
2390 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002391 for (p = start; *p && *p != ':' && *p != '%'; p++)
2392 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002393 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2394 while (stackblocksize() < len)
2395 growstackblock();
2396 q = stackblock();
2397 if (p != start) {
2398 memcpy(q, start, p - start);
2399 q += p - start;
2400 *q++ = '/';
2401 }
2402 strcpy(q, name);
2403 pathopt = NULL;
2404 if (*p == '%') {
2405 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002406 while (*p && *p != ':')
2407 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002408 }
2409 if (*p == ':')
2410 *path = p + 1;
2411 else
2412 *path = NULL;
2413 return stalloc(len);
2414}
2415
2416
2417/* ============ Prompt */
2418
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002419static smallint doprompt; /* if set, prompt the user */
2420static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002421
2422#if ENABLE_FEATURE_EDITING
2423static line_input_t *line_input_state;
2424static const char *cmdedit_prompt;
2425static void
2426putprompt(const char *s)
2427{
2428 if (ENABLE_ASH_EXPAND_PRMT) {
2429 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002430 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002431 return;
2432 }
2433 cmdedit_prompt = s;
2434}
2435#else
2436static void
2437putprompt(const char *s)
2438{
2439 out2str(s);
2440}
2441#endif
2442
2443#if ENABLE_ASH_EXPAND_PRMT
2444/* expandstr() needs parsing machinery, so it is far away ahead... */
2445static const char *expandstr(const char *ps);
2446#else
2447#define expandstr(s) s
2448#endif
2449
2450static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002451setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002452{
2453 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002454 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2455
2456 if (!do_set)
2457 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002458
2459 needprompt = 0;
2460
2461 switch (whichprompt) {
2462 case 1:
2463 prompt = ps1val();
2464 break;
2465 case 2:
2466 prompt = ps2val();
2467 break;
2468 default: /* 0 */
2469 prompt = nullstr;
2470 }
2471#if ENABLE_ASH_EXPAND_PRMT
2472 setstackmark(&smark);
2473 stalloc(stackblocksize());
2474#endif
2475 putprompt(expandstr(prompt));
2476#if ENABLE_ASH_EXPAND_PRMT
2477 popstackmark(&smark);
2478#endif
2479}
2480
2481
2482/* ============ The cd and pwd commands */
2483
2484#define CD_PHYSICAL 1
2485#define CD_PRINT 2
2486
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002487static int
2488cdopt(void)
2489{
2490 int flags = 0;
2491 int i, j;
2492
2493 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002494 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002495 if (i != j) {
2496 flags ^= CD_PHYSICAL;
2497 j = i;
2498 }
2499 }
2500
2501 return flags;
2502}
2503
2504/*
2505 * Update curdir (the name of the current directory) in response to a
2506 * cd command.
2507 */
2508static const char *
2509updatepwd(const char *dir)
2510{
2511 char *new;
2512 char *p;
2513 char *cdcomppath;
2514 const char *lim;
2515
2516 cdcomppath = ststrdup(dir);
2517 STARTSTACKSTR(new);
2518 if (*dir != '/') {
2519 if (curdir == nullstr)
2520 return 0;
2521 new = stack_putstr(curdir, new);
2522 }
2523 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002524 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002525 if (*dir != '/') {
2526 if (new[-1] != '/')
2527 USTPUTC('/', new);
2528 if (new > lim && *lim == '/')
2529 lim++;
2530 } else {
2531 USTPUTC('/', new);
2532 cdcomppath++;
2533 if (dir[1] == '/' && dir[2] != '/') {
2534 USTPUTC('/', new);
2535 cdcomppath++;
2536 lim++;
2537 }
2538 }
2539 p = strtok(cdcomppath, "/");
2540 while (p) {
2541 switch (*p) {
2542 case '.':
2543 if (p[1] == '.' && p[2] == '\0') {
2544 while (new > lim) {
2545 STUNPUTC(new);
2546 if (new[-1] == '/')
2547 break;
2548 }
2549 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002550 }
2551 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002552 break;
2553 /* fall through */
2554 default:
2555 new = stack_putstr(p, new);
2556 USTPUTC('/', new);
2557 }
2558 p = strtok(0, "/");
2559 }
2560 if (new > lim)
2561 STUNPUTC(new);
2562 *new = 0;
2563 return stackblock();
2564}
2565
2566/*
2567 * Find out what the current directory is. If we already know the current
2568 * directory, this routine returns immediately.
2569 */
2570static char *
2571getpwd(void)
2572{
Denis Vlasenko01631112007-12-16 17:20:38 +00002573 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002574 return dir ? dir : nullstr;
2575}
2576
2577static void
2578setpwd(const char *val, int setold)
2579{
2580 char *oldcur, *dir;
2581
2582 oldcur = dir = curdir;
2583
2584 if (setold) {
2585 setvar("OLDPWD", oldcur, VEXPORT);
2586 }
2587 INT_OFF;
2588 if (physdir != nullstr) {
2589 if (physdir != oldcur)
2590 free(physdir);
2591 physdir = nullstr;
2592 }
2593 if (oldcur == val || !val) {
2594 char *s = getpwd();
2595 physdir = s;
2596 if (!val)
2597 dir = s;
2598 } else
2599 dir = ckstrdup(val);
2600 if (oldcur != dir && oldcur != nullstr) {
2601 free(oldcur);
2602 }
2603 curdir = dir;
2604 INT_ON;
2605 setvar("PWD", dir, VEXPORT);
2606}
2607
2608static void hashcd(void);
2609
2610/*
2611 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2612 * know that the current directory has changed.
2613 */
2614static int
2615docd(const char *dest, int flags)
2616{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002617 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002618 int err;
2619
2620 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2621
2622 INT_OFF;
2623 if (!(flags & CD_PHYSICAL)) {
2624 dir = updatepwd(dest);
2625 if (dir)
2626 dest = dir;
2627 }
2628 err = chdir(dest);
2629 if (err)
2630 goto out;
2631 setpwd(dir, 1);
2632 hashcd();
2633 out:
2634 INT_ON;
2635 return err;
2636}
2637
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002638static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002639cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002640{
2641 const char *dest;
2642 const char *path;
2643 const char *p;
2644 char c;
2645 struct stat statb;
2646 int flags;
2647
2648 flags = cdopt();
2649 dest = *argptr;
2650 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002651 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002652 else if (LONE_DASH(dest)) {
2653 dest = bltinlookup("OLDPWD");
2654 flags |= CD_PRINT;
2655 }
2656 if (!dest)
2657 dest = nullstr;
2658 if (*dest == '/')
2659 goto step7;
2660 if (*dest == '.') {
2661 c = dest[1];
2662 dotdot:
2663 switch (c) {
2664 case '\0':
2665 case '/':
2666 goto step6;
2667 case '.':
2668 c = dest[2];
2669 if (c != '.')
2670 goto dotdot;
2671 }
2672 }
2673 if (!*dest)
2674 dest = ".";
2675 path = bltinlookup("CDPATH");
2676 if (!path) {
2677 step6:
2678 step7:
2679 p = dest;
2680 goto docd;
2681 }
2682 do {
2683 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002684 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002685 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2686 if (c && c != ':')
2687 flags |= CD_PRINT;
2688 docd:
2689 if (!docd(p, flags))
2690 goto out;
2691 break;
2692 }
2693 } while (path);
2694 ash_msg_and_raise_error("can't cd to %s", dest);
2695 /* NOTREACHED */
2696 out:
2697 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002698 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002699 return 0;
2700}
2701
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002702static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002703pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002704{
2705 int flags;
2706 const char *dir = curdir;
2707
2708 flags = cdopt();
2709 if (flags) {
2710 if (physdir == nullstr)
2711 setpwd(dir, 0);
2712 dir = physdir;
2713 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002714 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002715 return 0;
2716}
2717
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002718
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002719/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002720
Denis Vlasenko834dee72008-10-07 09:18:30 +00002721
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002722#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002723
Eric Andersenc470f442003-07-28 09:56:35 +00002724/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002725#define CWORD 0 /* character is nothing special */
2726#define CNL 1 /* newline character */
2727#define CBACK 2 /* a backslash character */
2728#define CSQUOTE 3 /* single quote */
2729#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002730#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002731#define CBQUOTE 6 /* backwards single quote */
2732#define CVAR 7 /* a dollar sign */
2733#define CENDVAR 8 /* a '}' character */
2734#define CLP 9 /* a left paren in arithmetic */
2735#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002736#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002737#define CCTL 12 /* like CWORD, except it must be escaped */
2738#define CSPCL 13 /* these terminate a word */
2739#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002740
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002741#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002742#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002743# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002744#endif
2745
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002746#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002747
Mike Frysinger98c52642009-04-02 10:02:37 +00002748#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002749# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002750#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002751# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002752#endif
Denys Vlasenko068d3862009-11-29 01:41:11 +01002753static const uint16_t S_I_T[] = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002754#if ENABLE_ASH_ALIAS
2755 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2756#endif
2757 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2758 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2759 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2760 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2761 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2762 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2763 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2764 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2765 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2766 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2767 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002768#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002769 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2770 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2771 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2772#endif
2773#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002774};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002775/* Constants below must match table above */
2776enum {
2777#if ENABLE_ASH_ALIAS
2778 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2779#endif
2780 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2781 CNL_CNL_CNL_CNL , /* 2 */
2782 CWORD_CCTL_CCTL_CWORD , /* 3 */
2783 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2784 CVAR_CVAR_CWORD_CVAR , /* 5 */
2785 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2786 CSPCL_CWORD_CWORD_CLP , /* 7 */
2787 CSPCL_CWORD_CWORD_CRP , /* 8 */
2788 CBACK_CBACK_CCTL_CBACK , /* 9 */
2789 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2790 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2791 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2792 CWORD_CWORD_CWORD_CWORD , /* 13 */
2793 CCTL_CCTL_CCTL_CCTL , /* 14 */
2794};
Eric Andersen2870d962001-07-02 17:27:21 +00002795
Denys Vlasenkocd716832009-11-28 22:14:02 +01002796/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2797 * caller must ensure proper cast on it if c is *char_ptr!
2798 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002799/* Values for syntax param */
2800#define BASESYNTAX 0 /* not in quotes */
2801#define DQSYNTAX 1 /* in double quotes */
2802#define SQSYNTAX 2 /* in single quotes */
2803#define ARISYNTAX 3 /* in arithmetic */
2804#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002805
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002806#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002807
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002808static int
2809SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002810{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00002811 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Denys Vlasenkocd716832009-11-28 22:14:02 +01002812# if ENABLE_ASH_ALIAS
2813 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002814 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2815 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2816 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2817 11, 3 /* "}~" */
2818 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002819# else
2820 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002821 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2822 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2823 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2824 10, 2 /* "}~" */
2825 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002826# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002827 const char *s;
2828 int indx;
2829
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002830 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002831 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002832# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002833 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002834 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002835 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002836# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002837 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002838 /* Cast is purely for paranoia here,
2839 * just in case someone passed signed char to us */
2840 if ((unsigned char)c >= CTL_FIRST
2841 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002842 ) {
2843 return CCTL;
2844 }
2845 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002846 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002847 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002848 indx = syntax_index_table[s - spec_symbls];
2849 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002850 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002851}
2852
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002853#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002854
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002855static const uint8_t syntax_index_table[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002856 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002857 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2858 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2867 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2868 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2890 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2891 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2892 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2893 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2894 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2895 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2896 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2897 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2898 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2899 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2900 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2901 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2902 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2903 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2904 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2905 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2916 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2917 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2918 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2919 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2920 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2921 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2922 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2949 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2950 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2951 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2954 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2955 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2982 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2983 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2984 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2985 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2986 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2987 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2988 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2989 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2990 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2991 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2992 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2993 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2994 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2995 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 141 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003113 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003114# if ENABLE_ASH_ALIAS
3115 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3116# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003117};
3118
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003119# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003120
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003121#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003122
Eric Andersen2870d962001-07-02 17:27:21 +00003123
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003124/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003125
Denis Vlasenko131ae172007-02-18 13:00:19 +00003126#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003127
3128#define ALIASINUSE 1
3129#define ALIASDEAD 2
3130
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003131struct alias {
3132 struct alias *next;
3133 char *name;
3134 char *val;
3135 int flag;
3136};
3137
Denis Vlasenko01631112007-12-16 17:20:38 +00003138
3139static struct alias **atab; // [ATABSIZE];
3140#define INIT_G_alias() do { \
3141 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3142} while (0)
3143
Eric Andersen2870d962001-07-02 17:27:21 +00003144
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003145static struct alias **
3146__lookupalias(const char *name) {
3147 unsigned int hashval;
3148 struct alias **app;
3149 const char *p;
3150 unsigned int ch;
3151
3152 p = name;
3153
3154 ch = (unsigned char)*p;
3155 hashval = ch << 4;
3156 while (ch) {
3157 hashval += ch;
3158 ch = (unsigned char)*++p;
3159 }
3160 app = &atab[hashval % ATABSIZE];
3161
3162 for (; *app; app = &(*app)->next) {
3163 if (strcmp(name, (*app)->name) == 0) {
3164 break;
3165 }
3166 }
3167
3168 return app;
3169}
3170
3171static struct alias *
3172lookupalias(const char *name, int check)
3173{
3174 struct alias *ap = *__lookupalias(name);
3175
3176 if (check && ap && (ap->flag & ALIASINUSE))
3177 return NULL;
3178 return ap;
3179}
3180
3181static struct alias *
3182freealias(struct alias *ap)
3183{
3184 struct alias *next;
3185
3186 if (ap->flag & ALIASINUSE) {
3187 ap->flag |= ALIASDEAD;
3188 return ap;
3189 }
3190
3191 next = ap->next;
3192 free(ap->name);
3193 free(ap->val);
3194 free(ap);
3195 return next;
3196}
Eric Andersencb57d552001-06-28 07:25:16 +00003197
Eric Andersenc470f442003-07-28 09:56:35 +00003198static void
3199setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003200{
3201 struct alias *ap, **app;
3202
3203 app = __lookupalias(name);
3204 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003205 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003206 if (ap) {
3207 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003208 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003209 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003210 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003211 ap->flag &= ~ALIASDEAD;
3212 } else {
3213 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003214 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003215 ap->name = ckstrdup(name);
3216 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003217 /*ap->flag = 0; - ckzalloc did it */
3218 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003219 *app = ap;
3220 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003221 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003222}
3223
Eric Andersenc470f442003-07-28 09:56:35 +00003224static int
3225unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003226{
Eric Andersencb57d552001-06-28 07:25:16 +00003227 struct alias **app;
3228
3229 app = __lookupalias(name);
3230
3231 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003232 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003233 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003234 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003235 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003236 }
3237
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003238 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003239}
3240
Eric Andersenc470f442003-07-28 09:56:35 +00003241static void
3242rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003243{
Eric Andersencb57d552001-06-28 07:25:16 +00003244 struct alias *ap, **app;
3245 int i;
3246
Denis Vlasenkob012b102007-02-19 22:43:01 +00003247 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003248 for (i = 0; i < ATABSIZE; i++) {
3249 app = &atab[i];
3250 for (ap = *app; ap; ap = *app) {
3251 *app = freealias(*app);
3252 if (ap == *app) {
3253 app = &ap->next;
3254 }
3255 }
3256 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003257 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003258}
3259
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003260static void
3261printalias(const struct alias *ap)
3262{
3263 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3264}
3265
Eric Andersencb57d552001-06-28 07:25:16 +00003266/*
3267 * TODO - sort output
3268 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003269static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003270aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003271{
3272 char *n, *v;
3273 int ret = 0;
3274 struct alias *ap;
3275
Denis Vlasenko68404f12008-03-17 09:00:54 +00003276 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003277 int i;
3278
Denis Vlasenko68404f12008-03-17 09:00:54 +00003279 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003280 for (ap = atab[i]; ap; ap = ap->next) {
3281 printalias(ap);
3282 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003283 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003284 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003285 }
3286 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003287 v = strchr(n+1, '=');
3288 if (v == NULL) { /* n+1: funny ksh stuff */
3289 ap = *__lookupalias(n);
3290 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003291 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003292 ret = 1;
3293 } else
3294 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003295 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003296 *v++ = '\0';
3297 setalias(n, v);
3298 }
3299 }
3300
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003301 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003302}
3303
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003304static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003305unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003306{
3307 int i;
3308
3309 while ((i = nextopt("a")) != '\0') {
3310 if (i == 'a') {
3311 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003312 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003313 }
3314 }
3315 for (i = 0; *argptr; argptr++) {
3316 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003317 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003318 i = 1;
3319 }
3320 }
3321
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003322 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003323}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003324
Denis Vlasenko131ae172007-02-18 13:00:19 +00003325#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003326
Eric Andersenc470f442003-07-28 09:56:35 +00003327
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003328/* ============ jobs.c */
3329
3330/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003331#define FORK_FG 0
3332#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003333#define FORK_NOJOB 2
3334
3335/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003336#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3337#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3338#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003339
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003340/*
3341 * A job structure contains information about a job. A job is either a
3342 * single process or a set of processes contained in a pipeline. In the
3343 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3344 * array of pids.
3345 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003346struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003347 pid_t ps_pid; /* process id */
3348 int ps_status; /* last process status from wait() */
3349 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003350};
3351
3352struct job {
3353 struct procstat ps0; /* status of process */
3354 struct procstat *ps; /* status or processes when more than one */
3355#if JOBS
3356 int stopstatus; /* status of a stopped job */
3357#endif
3358 uint32_t
3359 nprocs: 16, /* number of processes */
3360 state: 8,
3361#define JOBRUNNING 0 /* at least one proc running */
3362#define JOBSTOPPED 1 /* all procs are stopped */
3363#define JOBDONE 2 /* all procs are completed */
3364#if JOBS
3365 sigint: 1, /* job was killed by SIGINT */
3366 jobctl: 1, /* job running under job control */
3367#endif
3368 waited: 1, /* true if this entry has been waited for */
3369 used: 1, /* true if this entry is in used */
3370 changed: 1; /* true if status has changed */
3371 struct job *prev_job; /* previous job */
3372};
3373
Denis Vlasenko68404f12008-03-17 09:00:54 +00003374static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003375static int forkshell(struct job *, union node *, int);
3376static int waitforjob(struct job *);
3377
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003378#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003379enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003380#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003381#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003382static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003383static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003384#endif
3385
3386/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003387 * Ignore a signal.
3388 */
3389static void
3390ignoresig(int signo)
3391{
3392 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3393 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3394 /* No, need to do it */
3395 signal(signo, SIG_IGN);
3396 }
3397 sigmode[signo - 1] = S_HARD_IGN;
3398}
3399
3400/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003401 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003402 */
3403static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003404signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003405{
3406 gotsig[signo - 1] = 1;
3407
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003408 if (signo == SIGINT && !trap[SIGINT]) {
3409 if (!suppress_int) {
3410 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003411 raise_interrupt(); /* does not return */
3412 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003413 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003414 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003415 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003416 }
3417}
3418
3419/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003420 * Set the signal handler for the specified signal. The routine figures
3421 * out what it should be set to.
3422 */
3423static void
3424setsignal(int signo)
3425{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003426 char *t;
3427 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003428 struct sigaction act;
3429
3430 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003431 new_act = S_DFL;
3432 if (t != NULL) { /* trap for this sig is set */
3433 new_act = S_CATCH;
3434 if (t[0] == '\0') /* trap is "": ignore this sig */
3435 new_act = S_IGN;
3436 }
3437
3438 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003439 switch (signo) {
3440 case SIGINT:
3441 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003442 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003443 break;
3444 case SIGQUIT:
3445#if DEBUG
3446 if (debug)
3447 break;
3448#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003449 /* man bash:
3450 * "In all cases, bash ignores SIGQUIT. Non-builtin
3451 * commands run by bash have signal handlers
3452 * set to the values inherited by the shell
3453 * from its parent". */
3454 new_act = S_IGN;
3455 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003456 case SIGTERM:
3457 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003458 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003459 break;
3460#if JOBS
3461 case SIGTSTP:
3462 case SIGTTOU:
3463 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003464 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003465 break;
3466#endif
3467 }
3468 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003469//TODO: if !rootshell, we reset SIGQUIT to DFL,
3470//whereas we have to restore it to what shell got on entry
3471//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003472
3473 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003474 cur_act = *t;
3475 if (cur_act == 0) {
3476 /* current setting is not yet known */
3477 if (sigaction(signo, NULL, &act)) {
3478 /* pretend it worked; maybe we should give a warning,
3479 * but other shells don't. We don't alter sigmode,
3480 * so we retry every time.
3481 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003482 return;
3483 }
3484 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003485 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003486 if (mflag
3487 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3488 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003489 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003490 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003491 }
3492 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003493 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003494 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003495
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003496 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003497 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003498 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003499 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003500 break;
3501 case S_IGN:
3502 act.sa_handler = SIG_IGN;
3503 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003504 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003505
3506 /* flags and mask matter only if !DFL and !IGN, but we do it
3507 * for all cases for more deterministic behavior:
3508 */
3509 act.sa_flags = 0;
3510 sigfillset(&act.sa_mask);
3511
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003512 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003513
3514 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003515}
3516
3517/* mode flags for set_curjob */
3518#define CUR_DELETE 2
3519#define CUR_RUNNING 1
3520#define CUR_STOPPED 0
3521
3522/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003523#define DOWAIT_NONBLOCK WNOHANG
3524#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003525
3526#if JOBS
3527/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003528static int initialpgrp; //references:2
3529static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003530#endif
3531/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003532static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003533/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003534static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003535/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003536static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003537/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003538static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539
3540static void
3541set_curjob(struct job *jp, unsigned mode)
3542{
3543 struct job *jp1;
3544 struct job **jpp, **curp;
3545
3546 /* first remove from list */
3547 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003548 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003549 jp1 = *jpp;
3550 if (jp1 == jp)
3551 break;
3552 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003553 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003554 *jpp = jp1->prev_job;
3555
3556 /* Then re-insert in correct position */
3557 jpp = curp;
3558 switch (mode) {
3559 default:
3560#if DEBUG
3561 abort();
3562#endif
3563 case CUR_DELETE:
3564 /* job being deleted */
3565 break;
3566 case CUR_RUNNING:
3567 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003568 * put after all stopped jobs.
3569 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003570 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003571 jp1 = *jpp;
3572#if JOBS
3573 if (!jp1 || jp1->state != JOBSTOPPED)
3574#endif
3575 break;
3576 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003577 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003578 /* FALLTHROUGH */
3579#if JOBS
3580 case CUR_STOPPED:
3581#endif
3582 /* newly stopped job - becomes curjob */
3583 jp->prev_job = *jpp;
3584 *jpp = jp;
3585 break;
3586 }
3587}
3588
3589#if JOBS || DEBUG
3590static int
3591jobno(const struct job *jp)
3592{
3593 return jp - jobtab + 1;
3594}
3595#endif
3596
3597/*
3598 * Convert a job name to a job structure.
3599 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003600#if !JOBS
3601#define getjob(name, getctl) getjob(name)
3602#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003603static struct job *
3604getjob(const char *name, int getctl)
3605{
3606 struct job *jp;
3607 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003608 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003609 unsigned num;
3610 int c;
3611 const char *p;
3612 char *(*match)(const char *, const char *);
3613
3614 jp = curjob;
3615 p = name;
3616 if (!p)
3617 goto currentjob;
3618
3619 if (*p != '%')
3620 goto err;
3621
3622 c = *++p;
3623 if (!c)
3624 goto currentjob;
3625
3626 if (!p[1]) {
3627 if (c == '+' || c == '%') {
3628 currentjob:
3629 err_msg = "No current job";
3630 goto check;
3631 }
3632 if (c == '-') {
3633 if (jp)
3634 jp = jp->prev_job;
3635 err_msg = "No previous job";
3636 check:
3637 if (!jp)
3638 goto err;
3639 goto gotit;
3640 }
3641 }
3642
3643 if (is_number(p)) {
3644 num = atoi(p);
Denys Vlasenko07f7ea72014-09-08 17:21:52 +02003645 if (num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003646 jp = jobtab + num - 1;
3647 if (jp->used)
3648 goto gotit;
3649 goto err;
3650 }
3651 }
3652
3653 match = prefix;
3654 if (*p == '?') {
3655 match = strstr;
3656 p++;
3657 }
3658
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003659 found = NULL;
3660 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003661 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003662 if (found)
3663 goto err;
3664 found = jp;
3665 err_msg = "%s: ambiguous";
3666 }
3667 jp = jp->prev_job;
3668 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003669 if (!found)
3670 goto err;
3671 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003672
3673 gotit:
3674#if JOBS
3675 err_msg = "job %s not created under job control";
3676 if (getctl && jp->jobctl == 0)
3677 goto err;
3678#endif
3679 return jp;
3680 err:
3681 ash_msg_and_raise_error(err_msg, name);
3682}
3683
3684/*
3685 * Mark a job structure as unused.
3686 */
3687static void
3688freejob(struct job *jp)
3689{
3690 struct procstat *ps;
3691 int i;
3692
3693 INT_OFF;
3694 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003695 if (ps->ps_cmd != nullstr)
3696 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003697 }
3698 if (jp->ps != &jp->ps0)
3699 free(jp->ps);
3700 jp->used = 0;
3701 set_curjob(jp, CUR_DELETE);
3702 INT_ON;
3703}
3704
3705#if JOBS
3706static void
3707xtcsetpgrp(int fd, pid_t pgrp)
3708{
3709 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003710 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003711}
3712
3713/*
3714 * Turn job control on and off.
3715 *
3716 * Note: This code assumes that the third arg to ioctl is a character
3717 * pointer, which is true on Berkeley systems but not System V. Since
3718 * System V doesn't have job control yet, this isn't a problem now.
3719 *
3720 * Called with interrupts off.
3721 */
3722static void
3723setjobctl(int on)
3724{
3725 int fd;
3726 int pgrp;
3727
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003728 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003729 return;
3730 if (on) {
3731 int ofd;
3732 ofd = fd = open(_PATH_TTY, O_RDWR);
3733 if (fd < 0) {
3734 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3735 * That sometimes helps to acquire controlling tty.
3736 * Obviously, a workaround for bugs when someone
3737 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003738 fd = 2;
3739 while (!isatty(fd))
3740 if (--fd < 0)
3741 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003742 }
3743 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003744 if (ofd >= 0)
3745 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003746 if (fd < 0)
3747 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003748 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003749 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003750 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003751 pgrp = tcgetpgrp(fd);
3752 if (pgrp < 0) {
3753 out:
3754 ash_msg("can't access tty; job control turned off");
3755 mflag = on = 0;
3756 goto close;
3757 }
3758 if (pgrp == getpgrp())
3759 break;
3760 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003761 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003762 initialpgrp = pgrp;
3763
3764 setsignal(SIGTSTP);
3765 setsignal(SIGTTOU);
3766 setsignal(SIGTTIN);
3767 pgrp = rootpid;
3768 setpgid(0, pgrp);
3769 xtcsetpgrp(fd, pgrp);
3770 } else {
3771 /* turning job control off */
3772 fd = ttyfd;
3773 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003774 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003775 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003776 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003777 setpgid(0, pgrp);
3778 setsignal(SIGTSTP);
3779 setsignal(SIGTTOU);
3780 setsignal(SIGTTIN);
3781 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003782 if (fd >= 0)
3783 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003784 fd = -1;
3785 }
3786 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003787 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003788}
3789
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003790static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003791killcmd(int argc, char **argv)
3792{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003793 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003794 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003795 do {
3796 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003797 /*
3798 * "kill %N" - job kill
3799 * Converting to pgrp / pid kill
3800 */
3801 struct job *jp;
3802 char *dst;
3803 int j, n;
3804
3805 jp = getjob(argv[i], 0);
3806 /*
3807 * In jobs started under job control, we signal
3808 * entire process group by kill -PGRP_ID.
3809 * This happens, f.e., in interactive shell.
3810 *
3811 * Otherwise, we signal each child via
3812 * kill PID1 PID2 PID3.
3813 * Testcases:
3814 * sh -c 'sleep 1|sleep 1 & kill %1'
3815 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3816 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3817 */
3818 n = jp->nprocs; /* can't be 0 (I hope) */
3819 if (jp->jobctl)
3820 n = 1;
3821 dst = alloca(n * sizeof(int)*4);
3822 argv[i] = dst;
3823 for (j = 0; j < n; j++) {
3824 struct procstat *ps = &jp->ps[j];
3825 /* Skip non-running and not-stopped members
3826 * (i.e. dead members) of the job
3827 */
3828 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3829 continue;
3830 /*
3831 * kill_main has matching code to expect
3832 * leading space. Needed to not confuse
3833 * negative pids with "kill -SIGNAL_NO" syntax
3834 */
3835 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3836 }
3837 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003838 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003839 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003840 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003841 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003842}
3843
3844static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003845showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003846{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003847 struct procstat *ps;
3848 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003849
Denys Vlasenko285ad152009-12-04 23:02:27 +01003850 psend = jp->ps + jp->nprocs;
3851 for (ps = jp->ps + 1; ps < psend; ps++)
3852 printf(" | %s", ps->ps_cmd);
3853 outcslow('\n', stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003854 flush_stdout_stderr();
3855}
3856
3857
3858static int
3859restartjob(struct job *jp, int mode)
3860{
3861 struct procstat *ps;
3862 int i;
3863 int status;
3864 pid_t pgid;
3865
3866 INT_OFF;
3867 if (jp->state == JOBDONE)
3868 goto out;
3869 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003870 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003871 if (mode == FORK_FG)
3872 xtcsetpgrp(ttyfd, pgid);
3873 killpg(pgid, SIGCONT);
3874 ps = jp->ps;
3875 i = jp->nprocs;
3876 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003877 if (WIFSTOPPED(ps->ps_status)) {
3878 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003879 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003880 ps++;
3881 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003882 out:
3883 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3884 INT_ON;
3885 return status;
3886}
3887
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003888static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003889fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003890{
3891 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003892 int mode;
3893 int retval;
3894
3895 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3896 nextopt(nullstr);
3897 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003898 do {
3899 jp = getjob(*argv, 1);
3900 if (mode == FORK_BG) {
3901 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003902 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003903 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003904 out1str(jp->ps[0].ps_cmd);
3905 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003906 retval = restartjob(jp, mode);
3907 } while (*argv && *++argv);
3908 return retval;
3909}
3910#endif
3911
3912static int
3913sprint_status(char *s, int status, int sigonly)
3914{
3915 int col;
3916 int st;
3917
3918 col = 0;
3919 if (!WIFEXITED(status)) {
3920#if JOBS
3921 if (WIFSTOPPED(status))
3922 st = WSTOPSIG(status);
3923 else
3924#endif
3925 st = WTERMSIG(status);
3926 if (sigonly) {
3927 if (st == SIGINT || st == SIGPIPE)
3928 goto out;
3929#if JOBS
3930 if (WIFSTOPPED(status))
3931 goto out;
3932#endif
3933 }
3934 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003935//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003936 col = fmtstr(s, 32, strsignal(st));
3937 if (WCOREDUMP(status)) {
3938 col += fmtstr(s + col, 16, " (core dumped)");
3939 }
3940 } else if (!sigonly) {
3941 st = WEXITSTATUS(status);
3942 if (st)
3943 col = fmtstr(s, 16, "Done(%d)", st);
3944 else
3945 col = fmtstr(s, 16, "Done");
3946 }
3947 out:
3948 return col;
3949}
3950
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003951static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003952dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003953{
3954 int pid;
3955 int status;
3956 struct job *jp;
3957 struct job *thisjob;
3958 int state;
3959
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003960 TRACE(("dowait(0x%x) called\n", wait_flags));
3961
3962 /* Do a wait system call. If job control is compiled in, we accept
3963 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3964 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003965 if (doing_jobctl)
3966 wait_flags |= WUNTRACED;
3967 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003968 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3969 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003970 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003971 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003972
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003973 INT_OFF;
3974 thisjob = NULL;
3975 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003976 struct procstat *ps;
3977 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003978 if (jp->state == JOBDONE)
3979 continue;
3980 state = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003981 ps = jp->ps;
3982 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003983 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003984 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003985 TRACE(("Job %d: changing status of proc %d "
3986 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003987 jobno(jp), pid, ps->ps_status, status));
3988 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003989 thisjob = jp;
3990 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003991 if (ps->ps_status == -1)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003992 state = JOBRUNNING;
3993#if JOBS
3994 if (state == JOBRUNNING)
3995 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003996 if (WIFSTOPPED(ps->ps_status)) {
3997 jp->stopstatus = ps->ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003998 state = JOBSTOPPED;
3999 }
4000#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004001 } while (++ps < psend);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004002 if (thisjob)
4003 goto gotjob;
4004 }
4005#if JOBS
4006 if (!WIFSTOPPED(status))
4007#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004008 jobless--;
4009 goto out;
4010
4011 gotjob:
4012 if (state != JOBRUNNING) {
4013 thisjob->changed = 1;
4014
4015 if (thisjob->state != state) {
4016 TRACE(("Job %d: changing state from %d to %d\n",
4017 jobno(thisjob), thisjob->state, state));
4018 thisjob->state = state;
4019#if JOBS
4020 if (state == JOBSTOPPED) {
4021 set_curjob(thisjob, CUR_STOPPED);
4022 }
4023#endif
4024 }
4025 }
4026
4027 out:
4028 INT_ON;
4029
4030 if (thisjob && thisjob == job) {
4031 char s[48 + 1];
4032 int len;
4033
4034 len = sprint_status(s, status, 1);
4035 if (len) {
4036 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004037 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004038 out2str(s);
4039 }
4040 }
4041 return pid;
4042}
4043
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004044static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004045blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004046{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004047 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004048 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004049 raise_exception(EXSIG);
4050 return pid;
4051}
4052
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004053#if JOBS
4054static void
4055showjob(FILE *out, struct job *jp, int mode)
4056{
4057 struct procstat *ps;
4058 struct procstat *psend;
4059 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004060 int indent_col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004061 char s[80];
4062
4063 ps = jp->ps;
4064
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004065 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004066 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004067 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004068 return;
4069 }
4070
4071 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004072 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073
4074 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004075 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004076 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004077 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004078
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004079 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004080 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004081
4082 psend = ps + jp->nprocs;
4083
4084 if (jp->state == JOBRUNNING) {
4085 strcpy(s + col, "Running");
4086 col += sizeof("Running") - 1;
4087 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004088 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089 if (jp->state == JOBSTOPPED)
4090 status = jp->stopstatus;
4091 col += sprint_status(s + col, status, 0);
4092 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004093 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004094
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004095 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4096 * or prints several "PID | <cmdN>" lines,
4097 * depending on SHOW_PIDS bit.
4098 * We do not print status of individual processes
4099 * between PID and <cmdN>. bash does it, but not very well:
4100 * first line shows overall job status, not process status,
4101 * making it impossible to know 1st process status.
4102 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004103 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004104 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004105 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004106 s[0] = '\0';
4107 col = 33;
4108 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004109 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004111 fprintf(out, "%s%*c%s%s",
4112 s,
4113 33 - col >= 0 ? 33 - col : 0, ' ',
4114 ps == jp->ps ? "" : "| ",
4115 ps->ps_cmd
4116 );
4117 } while (++ps != psend);
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004118 outcslow('\n', out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004119
4120 jp->changed = 0;
4121
4122 if (jp->state == JOBDONE) {
4123 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4124 freejob(jp);
4125 }
4126}
4127
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004128/*
4129 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4130 * statuses have changed since the last call to showjobs.
4131 */
4132static void
4133showjobs(FILE *out, int mode)
4134{
4135 struct job *jp;
4136
Denys Vlasenko883cea42009-07-11 15:31:59 +02004137 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004139 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004140 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004141 continue;
4142
4143 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004144 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004145 showjob(out, jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004146 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004147 }
4148}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004149
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004150static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004151jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004152{
4153 int mode, m;
4154
4155 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004156 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004157 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004158 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004159 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004160 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004161 }
4162
4163 argv = argptr;
4164 if (*argv) {
4165 do
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004166 showjob(stdout, getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004167 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004168 } else {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004169 showjobs(stdout, mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004170 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004171
4172 return 0;
4173}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004174#endif /* JOBS */
4175
Michael Abbott359da5e2009-12-04 23:03:29 +01004176/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004177static int
4178getstatus(struct job *job)
4179{
4180 int status;
4181 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004182 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004183
Michael Abbott359da5e2009-12-04 23:03:29 +01004184 /* Fetch last member's status */
4185 ps = job->ps + job->nprocs - 1;
4186 status = ps->ps_status;
4187 if (pipefail) {
4188 /* "set -o pipefail" mode: use last _nonzero_ status */
4189 while (status == 0 && --ps >= job->ps)
4190 status = ps->ps_status;
4191 }
4192
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004193 retval = WEXITSTATUS(status);
4194 if (!WIFEXITED(status)) {
4195#if JOBS
4196 retval = WSTOPSIG(status);
4197 if (!WIFSTOPPED(status))
4198#endif
4199 {
4200 /* XXX: limits number of signals */
4201 retval = WTERMSIG(status);
4202#if JOBS
4203 if (retval == SIGINT)
4204 job->sigint = 1;
4205#endif
4206 }
4207 retval += 128;
4208 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004209 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004210 jobno(job), job->nprocs, status, retval));
4211 return retval;
4212}
4213
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004214static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004215waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004216{
4217 struct job *job;
4218 int retval;
4219 struct job *jp;
4220
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004221 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004222 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004223
4224 nextopt(nullstr);
4225 retval = 0;
4226
4227 argv = argptr;
4228 if (!*argv) {
4229 /* wait for all jobs */
4230 for (;;) {
4231 jp = curjob;
4232 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004233 if (!jp) /* no running procs */
4234 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004235 if (jp->state == JOBRUNNING)
4236 break;
4237 jp->waited = 1;
4238 jp = jp->prev_job;
4239 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004240 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004241 /* man bash:
4242 * "When bash is waiting for an asynchronous command via
4243 * the wait builtin, the reception of a signal for which a trap
4244 * has been set will cause the wait builtin to return immediately
4245 * with an exit status greater than 128, immediately after which
4246 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004247 *
4248 * blocking_wait_with_raise_on_sig raises signal handlers
4249 * if it gets no pid (pid < 0). However,
4250 * if child sends us a signal *and immediately exits*,
4251 * blocking_wait_with_raise_on_sig gets pid > 0
4252 * and does not handle pending_sig. Check this case: */
4253 if (pending_sig)
4254 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004255 }
4256 }
4257
4258 retval = 127;
4259 do {
4260 if (**argv != '%') {
4261 pid_t pid = number(*argv);
4262 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004263 while (1) {
4264 if (!job)
4265 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004266 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004267 break;
4268 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004269 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004270 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004271 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004272 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004273 /* loop until process terminated or stopped */
4274 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004275 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004276 job->waited = 1;
4277 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004278 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004279 } while (*++argv);
4280
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004281 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004282 return retval;
4283}
4284
4285static struct job *
4286growjobtab(void)
4287{
4288 size_t len;
4289 ptrdiff_t offset;
4290 struct job *jp, *jq;
4291
4292 len = njobs * sizeof(*jp);
4293 jq = jobtab;
4294 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4295
4296 offset = (char *)jp - (char *)jq;
4297 if (offset) {
4298 /* Relocate pointers */
4299 size_t l = len;
4300
4301 jq = (struct job *)((char *)jq + l);
4302 while (l) {
4303 l -= sizeof(*jp);
4304 jq--;
4305#define joff(p) ((struct job *)((char *)(p) + l))
4306#define jmove(p) (p) = (void *)((char *)(p) + offset)
4307 if (joff(jp)->ps == &jq->ps0)
4308 jmove(joff(jp)->ps);
4309 if (joff(jp)->prev_job)
4310 jmove(joff(jp)->prev_job);
4311 }
4312 if (curjob)
4313 jmove(curjob);
4314#undef joff
4315#undef jmove
4316 }
4317
4318 njobs += 4;
4319 jobtab = jp;
4320 jp = (struct job *)((char *)jp + len);
4321 jq = jp + 3;
4322 do {
4323 jq->used = 0;
4324 } while (--jq >= jp);
4325 return jp;
4326}
4327
4328/*
4329 * Return a new job structure.
4330 * Called with interrupts off.
4331 */
4332static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004333makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004334{
4335 int i;
4336 struct job *jp;
4337
4338 for (i = njobs, jp = jobtab; ; jp++) {
4339 if (--i < 0) {
4340 jp = growjobtab();
4341 break;
4342 }
4343 if (jp->used == 0)
4344 break;
4345 if (jp->state != JOBDONE || !jp->waited)
4346 continue;
4347#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004348 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004349 continue;
4350#endif
4351 freejob(jp);
4352 break;
4353 }
4354 memset(jp, 0, sizeof(*jp));
4355#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004356 /* jp->jobctl is a bitfield.
4357 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004358 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004359 jp->jobctl = 1;
4360#endif
4361 jp->prev_job = curjob;
4362 curjob = jp;
4363 jp->used = 1;
4364 jp->ps = &jp->ps0;
4365 if (nprocs > 1) {
4366 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4367 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004368 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004369 jobno(jp)));
4370 return jp;
4371}
4372
4373#if JOBS
4374/*
4375 * Return a string identifying a command (to be printed by the
4376 * jobs command).
4377 */
4378static char *cmdnextc;
4379
4380static void
4381cmdputs(const char *s)
4382{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004383 static const char vstype[VSTYPE + 1][3] = {
4384 "", "}", "-", "+", "?", "=",
4385 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004386 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004387 };
4388
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004389 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004390 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004391 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004392 unsigned char c;
4393 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004394 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004395
Denys Vlasenko46a14772009-12-10 21:27:13 +01004396 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004397 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4398 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004399 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004400 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004401 switch (c) {
4402 case CTLESC:
4403 c = *p++;
4404 break;
4405 case CTLVAR:
4406 subtype = *p++;
4407 if ((subtype & VSTYPE) == VSLENGTH)
4408 str = "${#";
4409 else
4410 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004411 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004412 case CTLENDVAR:
4413 str = "\"}" + !(quoted & 1);
4414 quoted >>= 1;
4415 subtype = 0;
4416 goto dostr;
4417 case CTLBACKQ:
4418 str = "$(...)";
4419 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004420#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004421 case CTLARI:
4422 str = "$((";
4423 goto dostr;
4424 case CTLENDARI:
4425 str = "))";
4426 goto dostr;
4427#endif
4428 case CTLQUOTEMARK:
4429 quoted ^= 1;
4430 c = '"';
4431 break;
4432 case '=':
4433 if (subtype == 0)
4434 break;
4435 if ((subtype & VSTYPE) != VSNORMAL)
4436 quoted <<= 1;
4437 str = vstype[subtype & VSTYPE];
4438 if (subtype & VSNUL)
4439 c = ':';
4440 else
4441 goto checkstr;
4442 break;
4443 case '\'':
4444 case '\\':
4445 case '"':
4446 case '$':
4447 /* These can only happen inside quotes */
4448 cc[0] = c;
4449 str = cc;
4450 c = '\\';
4451 break;
4452 default:
4453 break;
4454 }
4455 USTPUTC(c, nextc);
4456 checkstr:
4457 if (!str)
4458 continue;
4459 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004460 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004461 USTPUTC(c, nextc);
4462 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004463 } /* while *p++ not NUL */
4464
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004465 if (quoted & 1) {
4466 USTPUTC('"', nextc);
4467 }
4468 *nextc = 0;
4469 cmdnextc = nextc;
4470}
4471
4472/* cmdtxt() and cmdlist() call each other */
4473static void cmdtxt(union node *n);
4474
4475static void
4476cmdlist(union node *np, int sep)
4477{
4478 for (; np; np = np->narg.next) {
4479 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004480 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004481 cmdtxt(np);
4482 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004483 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004484 }
4485}
4486
4487static void
4488cmdtxt(union node *n)
4489{
4490 union node *np;
4491 struct nodelist *lp;
4492 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004493
4494 if (!n)
4495 return;
4496 switch (n->type) {
4497 default:
4498#if DEBUG
4499 abort();
4500#endif
4501 case NPIPE:
4502 lp = n->npipe.cmdlist;
4503 for (;;) {
4504 cmdtxt(lp->n);
4505 lp = lp->next;
4506 if (!lp)
4507 break;
4508 cmdputs(" | ");
4509 }
4510 break;
4511 case NSEMI:
4512 p = "; ";
4513 goto binop;
4514 case NAND:
4515 p = " && ";
4516 goto binop;
4517 case NOR:
4518 p = " || ";
4519 binop:
4520 cmdtxt(n->nbinary.ch1);
4521 cmdputs(p);
4522 n = n->nbinary.ch2;
4523 goto donode;
4524 case NREDIR:
4525 case NBACKGND:
4526 n = n->nredir.n;
4527 goto donode;
4528 case NNOT:
4529 cmdputs("!");
4530 n = n->nnot.com;
4531 donode:
4532 cmdtxt(n);
4533 break;
4534 case NIF:
4535 cmdputs("if ");
4536 cmdtxt(n->nif.test);
4537 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004538 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004539 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004540 cmdputs("; else ");
4541 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004542 } else {
4543 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004544 }
4545 p = "; fi";
4546 goto dotail;
4547 case NSUBSHELL:
4548 cmdputs("(");
4549 n = n->nredir.n;
4550 p = ")";
4551 goto dotail;
4552 case NWHILE:
4553 p = "while ";
4554 goto until;
4555 case NUNTIL:
4556 p = "until ";
4557 until:
4558 cmdputs(p);
4559 cmdtxt(n->nbinary.ch1);
4560 n = n->nbinary.ch2;
4561 p = "; done";
4562 dodo:
4563 cmdputs("; do ");
4564 dotail:
4565 cmdtxt(n);
4566 goto dotail2;
4567 case NFOR:
4568 cmdputs("for ");
4569 cmdputs(n->nfor.var);
4570 cmdputs(" in ");
4571 cmdlist(n->nfor.args, 1);
4572 n = n->nfor.body;
4573 p = "; done";
4574 goto dodo;
4575 case NDEFUN:
4576 cmdputs(n->narg.text);
4577 p = "() { ... }";
4578 goto dotail2;
4579 case NCMD:
4580 cmdlist(n->ncmd.args, 1);
4581 cmdlist(n->ncmd.redirect, 0);
4582 break;
4583 case NARG:
4584 p = n->narg.text;
4585 dotail2:
4586 cmdputs(p);
4587 break;
4588 case NHERE:
4589 case NXHERE:
4590 p = "<<...";
4591 goto dotail2;
4592 case NCASE:
4593 cmdputs("case ");
4594 cmdputs(n->ncase.expr->narg.text);
4595 cmdputs(" in ");
4596 for (np = n->ncase.cases; np; np = np->nclist.next) {
4597 cmdtxt(np->nclist.pattern);
4598 cmdputs(") ");
4599 cmdtxt(np->nclist.body);
4600 cmdputs(";; ");
4601 }
4602 p = "esac";
4603 goto dotail2;
4604 case NTO:
4605 p = ">";
4606 goto redir;
4607 case NCLOBBER:
4608 p = ">|";
4609 goto redir;
4610 case NAPPEND:
4611 p = ">>";
4612 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004613#if ENABLE_ASH_BASH_COMPAT
4614 case NTO2:
4615#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004616 case NTOFD:
4617 p = ">&";
4618 goto redir;
4619 case NFROM:
4620 p = "<";
4621 goto redir;
4622 case NFROMFD:
4623 p = "<&";
4624 goto redir;
4625 case NFROMTO:
4626 p = "<>";
4627 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004628 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004629 cmdputs(p);
4630 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004631 cmdputs(utoa(n->ndup.dupfd));
4632 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004633 }
4634 n = n->nfile.fname;
4635 goto donode;
4636 }
4637}
4638
4639static char *
4640commandtext(union node *n)
4641{
4642 char *name;
4643
4644 STARTSTACKSTR(cmdnextc);
4645 cmdtxt(n);
4646 name = stackblock();
4647 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4648 name, cmdnextc, cmdnextc));
4649 return ckstrdup(name);
4650}
4651#endif /* JOBS */
4652
4653/*
4654 * Fork off a subshell. If we are doing job control, give the subshell its
4655 * own process group. Jp is a job structure that the job is to be added to.
4656 * N is the command that will be evaluated by the child. Both jp and n may
4657 * be NULL. The mode parameter can be one of the following:
4658 * FORK_FG - Fork off a foreground process.
4659 * FORK_BG - Fork off a background process.
4660 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4661 * process group even if job control is on.
4662 *
4663 * When job control is turned off, background processes have their standard
4664 * input redirected to /dev/null (except for the second and later processes
4665 * in a pipeline).
4666 *
4667 * Called with interrupts off.
4668 */
4669/*
4670 * Clear traps on a fork.
4671 */
4672static void
4673clear_traps(void)
4674{
4675 char **tp;
4676
4677 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004678 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004679 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004680 if (trap_ptr == trap)
4681 free(*tp);
4682 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004683 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004684 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004685 setsignal(tp - trap);
4686 INT_ON;
4687 }
4688 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004689 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004690}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004691
4692/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004693static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004694
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004695/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004696static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004697forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004698{
4699 int oldlvl;
4700
4701 TRACE(("Child shell %d\n", getpid()));
4702 oldlvl = shlvl;
4703 shlvl++;
4704
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004705 /* man bash: "Non-builtin commands run by bash have signal handlers
4706 * set to the values inherited by the shell from its parent".
4707 * Do we do it correctly? */
4708
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004709 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004710
4711 if (mode == FORK_NOJOB /* is it `xxx` ? */
4712 && n && n->type == NCMD /* is it single cmd? */
4713 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004714 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004715 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4716 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4717 ) {
4718 TRACE(("Trap hack\n"));
4719 /* Awful hack for `trap` or $(trap).
4720 *
4721 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4722 * contains an example where "trap" is executed in a subshell:
4723 *
4724 * save_traps=$(trap)
4725 * ...
4726 * eval "$save_traps"
4727 *
4728 * Standard does not say that "trap" in subshell shall print
4729 * parent shell's traps. It only says that its output
4730 * must have suitable form, but then, in the above example
4731 * (which is not supposed to be normative), it implies that.
4732 *
4733 * bash (and probably other shell) does implement it
4734 * (traps are reset to defaults, but "trap" still shows them),
4735 * but as a result, "trap" logic is hopelessly messed up:
4736 *
4737 * # trap
4738 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4739 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4740 * # true | trap <--- trap is in subshell - no output (ditto)
4741 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4742 * trap -- 'echo Ho' SIGWINCH
4743 * # echo `(trap)` <--- in subshell in subshell - output
4744 * trap -- 'echo Ho' SIGWINCH
4745 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4746 * trap -- 'echo Ho' SIGWINCH
4747 *
4748 * The rules when to forget and when to not forget traps
4749 * get really complex and nonsensical.
4750 *
4751 * Our solution: ONLY bare $(trap) or `trap` is special.
4752 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004753 /* Save trap handler strings for trap builtin to print */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004754 trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004755 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004756 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004757 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004758#if JOBS
4759 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004760 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004761 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004762 pid_t pgrp;
4763
4764 if (jp->nprocs == 0)
4765 pgrp = getpid();
4766 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004767 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004768 /* this can fail because we are doing it in the parent also */
4769 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004770 if (mode == FORK_FG)
4771 xtcsetpgrp(ttyfd, pgrp);
4772 setsignal(SIGTSTP);
4773 setsignal(SIGTTOU);
4774 } else
4775#endif
4776 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004777 /* man bash: "When job control is not in effect,
4778 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004779 ignoresig(SIGINT);
4780 ignoresig(SIGQUIT);
4781 if (jp->nprocs == 0) {
4782 close(0);
4783 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004784 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004785 }
4786 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004787 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004788 if (iflag) { /* why if iflag only? */
4789 setsignal(SIGINT);
4790 setsignal(SIGTERM);
4791 }
4792 /* man bash:
4793 * "In all cases, bash ignores SIGQUIT. Non-builtin
4794 * commands run by bash have signal handlers
4795 * set to the values inherited by the shell
4796 * from its parent".
4797 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004798 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004799 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004800#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004801 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004802 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004803 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004804 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004805 /* "jobs": we do not want to clear job list for it,
4806 * instead we remove only _its_ own_ job from job list.
4807 * This makes "jobs .... | cat" more useful.
4808 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004809 freejob(curjob);
4810 return;
4811 }
4812#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004813 for (jp = curjob; jp; jp = jp->prev_job)
4814 freejob(jp);
4815 jobless = 0;
4816}
4817
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004818/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004819#if !JOBS
4820#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4821#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004822static void
4823forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4824{
4825 TRACE(("In parent shell: child = %d\n", pid));
4826 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004827 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4828 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004829 jobless++;
4830 return;
4831 }
4832#if JOBS
4833 if (mode != FORK_NOJOB && jp->jobctl) {
4834 int pgrp;
4835
4836 if (jp->nprocs == 0)
4837 pgrp = pid;
4838 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004839 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004840 /* This can fail because we are doing it in the child also */
4841 setpgid(pid, pgrp);
4842 }
4843#endif
4844 if (mode == FORK_BG) {
4845 backgndpid = pid; /* set $! */
4846 set_curjob(jp, CUR_RUNNING);
4847 }
4848 if (jp) {
4849 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004850 ps->ps_pid = pid;
4851 ps->ps_status = -1;
4852 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004853#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004854 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004855 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004856#endif
4857 }
4858}
4859
4860static int
4861forkshell(struct job *jp, union node *n, int mode)
4862{
4863 int pid;
4864
4865 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4866 pid = fork();
4867 if (pid < 0) {
4868 TRACE(("Fork failed, errno=%d", errno));
4869 if (jp)
4870 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004871 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004872 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004873 if (pid == 0) {
4874 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004875 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004876 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004877 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004878 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004879 return pid;
4880}
4881
4882/*
4883 * Wait for job to finish.
4884 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004885 * Under job control we have the problem that while a child process
4886 * is running interrupts generated by the user are sent to the child
4887 * but not to the shell. This means that an infinite loop started by
4888 * an interactive user may be hard to kill. With job control turned off,
4889 * an interactive user may place an interactive program inside a loop.
4890 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004891 * these interrupts to also abort the loop. The approach we take here
4892 * is to have the shell ignore interrupt signals while waiting for a
4893 * foreground process to terminate, and then send itself an interrupt
4894 * signal if the child process was terminated by an interrupt signal.
4895 * Unfortunately, some programs want to do a bit of cleanup and then
4896 * exit on interrupt; unless these processes terminate themselves by
4897 * sending a signal to themselves (instead of calling exit) they will
4898 * confuse this approach.
4899 *
4900 * Called with interrupts off.
4901 */
4902static int
4903waitforjob(struct job *jp)
4904{
4905 int st;
4906
4907 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004908
4909 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004910 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004911 /* In non-interactive shells, we _can_ get
4912 * a keyboard signal here and be EINTRed,
4913 * but we just loop back, waiting for command to complete.
4914 *
4915 * man bash:
4916 * "If bash is waiting for a command to complete and receives
4917 * a signal for which a trap has been set, the trap
4918 * will not be executed until the command completes."
4919 *
4920 * Reality is that even if trap is not set, bash
4921 * will not act on the signal until command completes.
4922 * Try this. sleep5intoff.c:
4923 * #include <signal.h>
4924 * #include <unistd.h>
4925 * int main() {
4926 * sigset_t set;
4927 * sigemptyset(&set);
4928 * sigaddset(&set, SIGINT);
4929 * sigaddset(&set, SIGQUIT);
4930 * sigprocmask(SIG_BLOCK, &set, NULL);
4931 * sleep(5);
4932 * return 0;
4933 * }
4934 * $ bash -c './sleep5intoff; echo hi'
4935 * ^C^C^C^C <--- pressing ^C once a second
4936 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004937 * $ bash -c './sleep5intoff; echo hi'
4938 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4939 * $ _
4940 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004941 dowait(DOWAIT_BLOCK, jp);
4942 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004943 INT_ON;
4944
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004945 st = getstatus(jp);
4946#if JOBS
4947 if (jp->jobctl) {
4948 xtcsetpgrp(ttyfd, rootpid);
4949 /*
4950 * This is truly gross.
4951 * If we're doing job control, then we did a TIOCSPGRP which
4952 * caused us (the shell) to no longer be in the controlling
4953 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4954 * intuit from the subprocess exit status whether a SIGINT
4955 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4956 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004957 if (jp->sigint) /* TODO: do the same with all signals */
4958 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004959 }
4960 if (jp->state == JOBDONE)
4961#endif
4962 freejob(jp);
4963 return st;
4964}
4965
4966/*
4967 * return 1 if there are stopped jobs, otherwise 0
4968 */
4969static int
4970stoppedjobs(void)
4971{
4972 struct job *jp;
4973 int retval;
4974
4975 retval = 0;
4976 if (job_warning)
4977 goto out;
4978 jp = curjob;
4979 if (jp && jp->state == JOBSTOPPED) {
4980 out2str("You have stopped jobs.\n");
4981 job_warning = 2;
4982 retval++;
4983 }
4984 out:
4985 return retval;
4986}
4987
4988
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004989/* ============ redir.c
4990 *
4991 * Code for dealing with input/output redirection.
4992 */
4993
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01004994#undef EMPTY
4995#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004996#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00004997#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004998
4999/*
5000 * Open a file in noclobber mode.
5001 * The code was copied from bash.
5002 */
5003static int
5004noclobberopen(const char *fname)
5005{
5006 int r, fd;
5007 struct stat finfo, finfo2;
5008
5009 /*
5010 * If the file exists and is a regular file, return an error
5011 * immediately.
5012 */
5013 r = stat(fname, &finfo);
5014 if (r == 0 && S_ISREG(finfo.st_mode)) {
5015 errno = EEXIST;
5016 return -1;
5017 }
5018
5019 /*
5020 * If the file was not present (r != 0), make sure we open it
5021 * exclusively so that if it is created before we open it, our open
5022 * will fail. Make sure that we do not truncate an existing file.
5023 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5024 * file was not a regular file, we leave O_EXCL off.
5025 */
5026 if (r != 0)
5027 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5028 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5029
5030 /* If the open failed, return the file descriptor right away. */
5031 if (fd < 0)
5032 return fd;
5033
5034 /*
5035 * OK, the open succeeded, but the file may have been changed from a
5036 * non-regular file to a regular file between the stat and the open.
5037 * We are assuming that the O_EXCL open handles the case where FILENAME
5038 * did not exist and is symlinked to an existing file between the stat
5039 * and open.
5040 */
5041
5042 /*
5043 * If we can open it and fstat the file descriptor, and neither check
5044 * revealed that it was a regular file, and the file has not been
5045 * replaced, return the file descriptor.
5046 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005047 if (fstat(fd, &finfo2) == 0
5048 && !S_ISREG(finfo2.st_mode)
5049 && finfo.st_dev == finfo2.st_dev
5050 && finfo.st_ino == finfo2.st_ino
5051 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005052 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005053 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005054
5055 /* The file has been replaced. badness. */
5056 close(fd);
5057 errno = EEXIST;
5058 return -1;
5059}
5060
5061/*
5062 * Handle here documents. Normally we fork off a process to write the
5063 * data to a pipe. If the document is short, we can stuff the data in
5064 * the pipe without forking.
5065 */
5066/* openhere needs this forward reference */
5067static void expandhere(union node *arg, int fd);
5068static int
5069openhere(union node *redir)
5070{
5071 int pip[2];
5072 size_t len = 0;
5073
5074 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005075 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005076 if (redir->type == NHERE) {
5077 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005078 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005079 full_write(pip[1], redir->nhere.doc->narg.text, len);
5080 goto out;
5081 }
5082 }
5083 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005084 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005085 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005086 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5087 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5088 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5089 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005090 signal(SIGPIPE, SIG_DFL);
5091 if (redir->type == NHERE)
5092 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005093 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005094 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005095 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005096 }
5097 out:
5098 close(pip[1]);
5099 return pip[0];
5100}
5101
5102static int
5103openredirect(union node *redir)
5104{
5105 char *fname;
5106 int f;
5107
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02005108 fname = redir->nfile.expfname;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005109 switch (redir->nfile.type) {
5110 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005111 f = open(fname, O_RDONLY);
5112 if (f < 0)
5113 goto eopen;
5114 break;
5115 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005116 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005117 if (f < 0)
5118 goto ecreate;
5119 break;
5120 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005121#if ENABLE_ASH_BASH_COMPAT
5122 case NTO2:
5123#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005124 /* Take care of noclobber mode. */
5125 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005126 f = noclobberopen(fname);
5127 if (f < 0)
5128 goto ecreate;
5129 break;
5130 }
5131 /* FALLTHROUGH */
5132 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005133 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5134 if (f < 0)
5135 goto ecreate;
5136 break;
5137 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005138 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5139 if (f < 0)
5140 goto ecreate;
5141 break;
5142 default:
5143#if DEBUG
5144 abort();
5145#endif
5146 /* Fall through to eliminate warning. */
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005147/* Our single caller does this itself */
Denis Vlasenko0b769642008-07-24 07:54:57 +00005148// case NTOFD:
5149// case NFROMFD:
5150// f = -1;
5151// break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005152 case NHERE:
5153 case NXHERE:
5154 f = openhere(redir);
5155 break;
5156 }
5157
5158 return f;
5159 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005160 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005161 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005162 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005163}
5164
5165/*
5166 * Copy a file descriptor to be >= to. Returns -1
5167 * if the source file descriptor is closed, EMPTY if there are no unused
5168 * file descriptors left.
5169 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005170/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5171 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005172enum {
5173 COPYFD_EXACT = (int)~(INT_MAX),
5174 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5175};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005176static int
5177copyfd(int from, int to)
5178{
5179 int newfd;
5180
Denis Vlasenko5a867312008-07-24 19:46:38 +00005181 if (to & COPYFD_EXACT) {
5182 to &= ~COPYFD_EXACT;
5183 /*if (from != to)*/
5184 newfd = dup2(from, to);
5185 } else {
5186 newfd = fcntl(from, F_DUPFD, to);
5187 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005188 if (newfd < 0) {
5189 if (errno == EMFILE)
5190 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005191 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005192 ash_msg_and_raise_error("%d: %m", from);
5193 }
5194 return newfd;
5195}
5196
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005197/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005198struct two_fd_t {
5199 int orig, copy;
5200};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005201struct redirtab {
5202 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005203 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005204 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005205 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005206};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005207#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005208
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005209static int need_to_remember(struct redirtab *rp, int fd)
5210{
5211 int i;
5212
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005213 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005214 return 0;
5215
5216 for (i = 0; i < rp->pair_count; i++) {
5217 if (rp->two_fd[i].orig == fd) {
5218 /* already remembered */
5219 return 0;
5220 }
5221 }
5222 return 1;
5223}
5224
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005225/* "hidden" fd is a fd used to read scripts, or a copy of such */
5226static int is_hidden_fd(struct redirtab *rp, int fd)
5227{
5228 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005229 struct parsefile *pf;
5230
5231 if (fd == -1)
5232 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005233 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005234 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005235 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005236 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005237 * $ ash # running ash interactively
5238 * $ . ./script.sh
5239 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005240 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005241 * it's still ok to use it: "read" builtin uses it,
5242 * why should we cripple "exec" builtin?
5243 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005244 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005245 return 1;
5246 }
5247 pf = pf->prev;
5248 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005249
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005250 if (!rp)
5251 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005252 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005253 fd |= COPYFD_RESTORE;
5254 for (i = 0; i < rp->pair_count; i++) {
5255 if (rp->two_fd[i].copy == fd) {
5256 return 1;
5257 }
5258 }
5259 return 0;
5260}
5261
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005262/*
5263 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5264 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005265 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005266 */
5267/* flags passed to redirect */
5268#define REDIR_PUSH 01 /* save previous values of file descriptors */
5269#define REDIR_SAVEFD2 03 /* set preverrout */
5270static void
5271redirect(union node *redir, int flags)
5272{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005273 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005274 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005275 int i;
5276 int fd;
5277 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005278 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005279
Denis Vlasenko01631112007-12-16 17:20:38 +00005280 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005281 if (!redir) {
5282 return;
5283 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005284
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005285 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005286 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005287 INT_OFF;
5288 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005289 union node *tmp = redir;
5290 do {
5291 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005292#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005293 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005294 sv_pos++;
5295#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005296 tmp = tmp->nfile.next;
5297 } while (tmp);
5298 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005299 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005300 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005301 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005302 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005303 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005304 while (sv_pos > 0) {
5305 sv_pos--;
5306 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5307 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005308 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005309
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005310 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005311 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005312 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005313 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005314 right_fd = redir->ndup.dupfd;
5315 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005316 /* redirect from/to same file descriptor? */
5317 if (right_fd == fd)
5318 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005319 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005320 if (is_hidden_fd(sv, right_fd)) {
5321 errno = EBADF; /* as if it is closed */
5322 ash_msg_and_raise_error("%d: %m", right_fd);
5323 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005324 newfd = -1;
5325 } else {
5326 newfd = openredirect(redir); /* always >= 0 */
5327 if (fd == newfd) {
5328 /* Descriptor wasn't open before redirect.
5329 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005330 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005331 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005332 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005333 continue;
5334 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005335 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005336#if ENABLE_ASH_BASH_COMPAT
5337 redirect_more:
5338#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005339 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005340 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005341 /* Careful to not accidentally "save"
5342 * to the same fd as right side fd in N>&M */
5343 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5344 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005345/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5346 * are closed in popredir() in the child, preventing them from leaking
5347 * into child. (popredir() also cleans up the mess in case of failures)
5348 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005349 if (i == -1) {
5350 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005351 if (i != EBADF) {
5352 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005353 if (newfd >= 0)
5354 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005355 errno = i;
5356 ash_msg_and_raise_error("%d: %m", fd);
5357 /* NOTREACHED */
5358 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005359 /* EBADF: it is not open - good, remember to close it */
5360 remember_to_close:
5361 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005362 } else { /* fd is open, save its copy */
5363 /* "exec fd>&-" should not close fds
5364 * which point to script file(s).
5365 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005366 if (is_hidden_fd(sv, fd))
5367 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005368 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005369 if (fd == 2)
5370 copied_fd2 = i;
5371 sv->two_fd[sv_pos].orig = fd;
5372 sv->two_fd[sv_pos].copy = i;
5373 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005374 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005375 if (newfd < 0) {
5376 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005377 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005378 /* Don't want to trigger debugging */
5379 if (fd != -1)
5380 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005381 } else {
5382 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005383 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005384 } else if (fd != newfd) { /* move newfd to fd */
5385 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005386#if ENABLE_ASH_BASH_COMPAT
5387 if (!(redir->nfile.type == NTO2 && fd == 2))
5388#endif
5389 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005390 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005391#if ENABLE_ASH_BASH_COMPAT
5392 if (redir->nfile.type == NTO2 && fd == 1) {
5393 /* We already redirected it to fd 1, now copy it to 2 */
5394 newfd = 1;
5395 fd = 2;
5396 goto redirect_more;
5397 }
5398#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005399 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005400
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005401 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005402 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5403 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005404}
5405
5406/*
5407 * Undo the effects of the last redirection.
5408 */
5409static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005410popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005411{
5412 struct redirtab *rp;
5413 int i;
5414
Denis Vlasenko01631112007-12-16 17:20:38 +00005415 if (--g_nullredirs >= 0)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005416 return;
5417 INT_OFF;
5418 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005419 for (i = 0; i < rp->pair_count; i++) {
5420 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005421 int copy = rp->two_fd[i].copy;
5422 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005423 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005424 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005425 continue;
5426 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005427 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005428 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005429 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005430 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005431 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005432 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005433 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005434 }
5435 }
5436 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005437 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005438 free(rp);
5439 INT_ON;
5440}
5441
5442/*
5443 * Undo all redirections. Called on error or interrupt.
5444 */
5445
5446/*
5447 * Discard all saved file descriptors.
5448 */
5449static void
5450clearredir(int drop)
5451{
5452 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005453 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005454 if (!redirlist)
5455 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005456 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005457 }
5458}
5459
5460static int
5461redirectsafe(union node *redir, int flags)
5462{
5463 int err;
5464 volatile int saveint;
5465 struct jmploc *volatile savehandler = exception_handler;
5466 struct jmploc jmploc;
5467
5468 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005469 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5470 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005471 if (!err) {
5472 exception_handler = &jmploc;
5473 redirect(redir, flags);
5474 }
5475 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005476 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005477 longjmp(exception_handler->loc, 1);
5478 RESTORE_INT(saveint);
5479 return err;
5480}
5481
5482
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005483/* ============ Routines to expand arguments to commands
5484 *
5485 * We have to deal with backquotes, shell variables, and file metacharacters.
5486 */
5487
Mike Frysinger98c52642009-04-02 10:02:37 +00005488#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005489static arith_t
5490ash_arith(const char *s)
5491{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005492 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005493 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005494
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005495 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005496 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005497 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005498
5499 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005500 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005501 if (math_state.errmsg)
5502 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005503 INT_ON;
5504
5505 return result;
5506}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005507#endif
5508
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005509/*
5510 * expandarg flags
5511 */
5512#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5513#define EXP_TILDE 0x2 /* do normal tilde expansion */
5514#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5515#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5516#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005517#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005518#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5519#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005520#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005521/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005522 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005523 */
5524#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5525#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005526#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5527#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005528#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005529
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005530/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005531#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005532/* Do not skip NUL characters. */
5533#define QUOTES_KEEPNUL EXP_TILDE
5534
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005535/*
5536 * Structure specifying which parts of the string should be searched
5537 * for IFS characters.
5538 */
5539struct ifsregion {
5540 struct ifsregion *next; /* next region in list */
5541 int begoff; /* offset of start of region */
5542 int endoff; /* offset of end of region */
5543 int nulonly; /* search for nul bytes only */
5544};
5545
5546struct arglist {
5547 struct strlist *list;
5548 struct strlist **lastp;
5549};
5550
5551/* output of current string */
5552static char *expdest;
5553/* list of back quote expressions */
5554static struct nodelist *argbackq;
5555/* first struct in list of ifs regions */
5556static struct ifsregion ifsfirst;
5557/* last struct in list */
5558static struct ifsregion *ifslastp;
5559/* holds expanded arg list */
5560static struct arglist exparg;
5561
5562/*
5563 * Our own itoa().
5564 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005565#if !ENABLE_SH_MATH_SUPPORT
5566/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5567typedef long arith_t;
5568# define ARITH_FMT "%ld"
5569#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005570static int
5571cvtnum(arith_t num)
5572{
5573 int len;
5574
5575 expdest = makestrspace(32, expdest);
Denys Vlasenkobed7c812010-09-16 11:50:46 +02005576 len = fmtstr(expdest, 32, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005577 STADJUST(len, expdest);
5578 return len;
5579}
5580
5581static size_t
5582esclen(const char *start, const char *p)
5583{
5584 size_t esc = 0;
5585
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005586 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005587 esc++;
5588 }
5589 return esc;
5590}
5591
5592/*
5593 * Remove any CTLESC characters from a string.
5594 */
5595static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005596rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005597{
Ron Yorston417622c2015-05-18 09:59:14 +02005598 static const char qchars[] ALIGN1 = {
5599 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005600
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005601 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005602 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005603 unsigned protect_against_glob;
5604 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005605 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005606
Ron Yorston417622c2015-05-18 09:59:14 +02005607 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005608 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005609 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005610
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005611 q = p;
5612 r = str;
5613 if (flag & RMESCAPE_ALLOC) {
5614 size_t len = p - str;
5615 size_t fulllen = len + strlen(p) + 1;
5616
5617 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005618 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005619 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005620 /* p and str may be invalidated by makestrspace */
5621 str = (char *)stackblock() + strloc;
5622 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005623 } else if (flag & RMESCAPE_HEAP) {
5624 r = ckmalloc(fulllen);
5625 } else {
5626 r = stalloc(fulllen);
5627 }
5628 q = r;
5629 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005630 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005631 }
5632 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005633
Ron Yorston549deab2015-05-18 09:57:51 +02005634 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005635 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005636 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005637 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005638 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005639// Note: both inquotes and protect_against_glob only affect whether
5640// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005641 inquotes = ~inquotes;
5642 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005643 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005644 continue;
5645 }
Ron Yorston549deab2015-05-18 09:57:51 +02005646 if ((unsigned char)*p == CTLESC) {
5647 p++;
5648 if (protect_against_glob) {
5649 *q++ = '\\';
5650 }
5651 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005652 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005653 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005654 goto copy;
5655 }
Ron Yorston417622c2015-05-18 09:59:14 +02005656#if ENABLE_ASH_BASH_COMPAT
5657 else if (*p == '/' && slash) {
5658 /* stop handling globbing and mark location of slash */
5659 globbing = slash = 0;
5660 *p = CTLESC;
5661 }
5662#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005663 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005664 copy:
5665 *q++ = *p++;
5666 }
5667 *q = '\0';
5668 if (flag & RMESCAPE_GROW) {
5669 expdest = r;
5670 STADJUST(q - r + 1, expdest);
5671 }
5672 return r;
5673}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005674#define pmatch(a, b) !fnmatch((a), (b), 0)
5675
5676/*
5677 * Prepare a pattern for a expmeta (internal glob(3)) call.
5678 *
5679 * Returns an stalloced string.
5680 */
5681static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005682preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005683{
Ron Yorston549deab2015-05-18 09:57:51 +02005684 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005685}
5686
5687/*
5688 * Put a string on the stack.
5689 */
5690static void
5691memtodest(const char *p, size_t len, int syntax, int quotes)
5692{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005693 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005694
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005695 if (!len)
5696 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005697
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005698 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5699
5700 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005701 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005702 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005703 int n = SIT(c, syntax);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005704 if ((quotes & QUOTES_ESC) &&
Ron Yorston549deab2015-05-18 09:57:51 +02005705 ((n == CCTL) ||
5706 (((quotes & EXP_FULL) || syntax != BASESYNTAX) &&
5707 n == CBACK)))
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005708 USTPUTC(CTLESC, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005709 } else if (!(quotes & QUOTES_KEEPNUL))
5710 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005711 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005712 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005713
5714 expdest = q;
5715}
5716
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005717static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005718strtodest(const char *p, int syntax, int quotes)
5719{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005720 size_t len = strlen(p);
5721 memtodest(p, len, syntax, quotes);
5722 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005723}
5724
5725/*
5726 * Record the fact that we have to scan this region of the
5727 * string for IFS characters.
5728 */
5729static void
5730recordregion(int start, int end, int nulonly)
5731{
5732 struct ifsregion *ifsp;
5733
5734 if (ifslastp == NULL) {
5735 ifsp = &ifsfirst;
5736 } else {
5737 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005738 ifsp = ckzalloc(sizeof(*ifsp));
5739 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005740 ifslastp->next = ifsp;
5741 INT_ON;
5742 }
5743 ifslastp = ifsp;
5744 ifslastp->begoff = start;
5745 ifslastp->endoff = end;
5746 ifslastp->nulonly = nulonly;
5747}
5748
5749static void
5750removerecordregions(int endoff)
5751{
5752 if (ifslastp == NULL)
5753 return;
5754
5755 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005756 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005757 struct ifsregion *ifsp;
5758 INT_OFF;
5759 ifsp = ifsfirst.next->next;
5760 free(ifsfirst.next);
5761 ifsfirst.next = ifsp;
5762 INT_ON;
5763 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005764 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005765 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005766 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005767 ifslastp = &ifsfirst;
5768 ifsfirst.endoff = endoff;
5769 }
5770 return;
5771 }
5772
5773 ifslastp = &ifsfirst;
5774 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005775 ifslastp = ifslastp->next;
5776 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005777 struct ifsregion *ifsp;
5778 INT_OFF;
5779 ifsp = ifslastp->next->next;
5780 free(ifslastp->next);
5781 ifslastp->next = ifsp;
5782 INT_ON;
5783 }
5784 if (ifslastp->endoff > endoff)
5785 ifslastp->endoff = endoff;
5786}
5787
5788static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005789exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005790{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005791 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005792 char *name;
5793 struct passwd *pw;
5794 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005795 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005796
5797 name = p + 1;
5798
5799 while ((c = *++p) != '\0') {
5800 switch (c) {
5801 case CTLESC:
5802 return startp;
5803 case CTLQUOTEMARK:
5804 return startp;
5805 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005806 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005807 goto done;
5808 break;
5809 case '/':
5810 case CTLENDVAR:
5811 goto done;
5812 }
5813 }
5814 done:
5815 *p = '\0';
5816 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005817 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005818 } else {
5819 pw = getpwnam(name);
5820 if (pw == NULL)
5821 goto lose;
5822 home = pw->pw_dir;
5823 }
5824 if (!home || !*home)
5825 goto lose;
5826 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005827 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005828 return p;
5829 lose:
5830 *p = c;
5831 return startp;
5832}
5833
5834/*
5835 * Execute a command inside back quotes. If it's a builtin command, we
5836 * want to save its output in a block obtained from malloc. Otherwise
5837 * we fork off a subprocess and get the output of the command via a pipe.
5838 * Should be called with interrupts off.
5839 */
5840struct backcmd { /* result of evalbackcmd */
5841 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005842 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005843 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005844 struct job *jp; /* job structure for command */
5845};
5846
5847/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005848static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005849#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02005850static void evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005851
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005852static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005853evalbackcmd(union node *n, struct backcmd *result)
5854{
5855 int saveherefd;
5856
5857 result->fd = -1;
5858 result->buf = NULL;
5859 result->nleft = 0;
5860 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005861 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005862 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005863
5864 saveherefd = herefd;
5865 herefd = -1;
5866
5867 {
5868 int pip[2];
5869 struct job *jp;
5870
5871 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005872 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005873 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005874 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5875 FORCE_INT_ON;
5876 close(pip[0]);
5877 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005878 /*close(1);*/
5879 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005880 close(pip[1]);
5881 }
5882 eflag = 0;
5883 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5884 /* NOTREACHED */
5885 }
5886 close(pip[1]);
5887 result->fd = pip[0];
5888 result->jp = jp;
5889 }
5890 herefd = saveherefd;
5891 out:
5892 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5893 result->fd, result->buf, result->nleft, result->jp));
5894}
5895
5896/*
5897 * Expand stuff in backwards quotes.
5898 */
5899static void
Ron Yorston549deab2015-05-18 09:57:51 +02005900expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005901{
5902 struct backcmd in;
5903 int i;
5904 char buf[128];
5905 char *p;
5906 char *dest;
5907 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02005908 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005909 struct stackmark smark;
5910
5911 INT_OFF;
5912 setstackmark(&smark);
5913 dest = expdest;
5914 startloc = dest - (char *)stackblock();
5915 grabstackstr(dest);
5916 evalbackcmd(cmd, &in);
5917 popstackmark(&smark);
5918
5919 p = in.buf;
5920 i = in.nleft;
5921 if (i == 0)
5922 goto read;
5923 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02005924 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005925 read:
5926 if (in.fd < 0)
5927 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01005928 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005929 TRACE(("expbackq: read returns %d\n", i));
5930 if (i <= 0)
5931 break;
5932 p = buf;
5933 }
5934
Denis Vlasenko60818682007-09-28 22:07:23 +00005935 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005936 if (in.fd >= 0) {
5937 close(in.fd);
5938 back_exitstatus = waitforjob(in.jp);
5939 }
5940 INT_ON;
5941
5942 /* Eat all trailing newlines */
5943 dest = expdest;
5944 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5945 STUNPUTC(dest);
5946 expdest = dest;
5947
Ron Yorston549deab2015-05-18 09:57:51 +02005948 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005949 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005950 TRACE(("evalbackq: size:%d:'%.*s'\n",
5951 (int)((dest - (char *)stackblock()) - startloc),
5952 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005953 stackblock() + startloc));
5954}
5955
Mike Frysinger98c52642009-04-02 10:02:37 +00005956#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005957/*
5958 * Expand arithmetic expression. Backup to start of expression,
5959 * evaluate, place result in (backed up) result, adjust string position.
5960 */
5961static void
Ron Yorston549deab2015-05-18 09:57:51 +02005962expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005963{
5964 char *p, *start;
5965 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966 int len;
5967
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005968 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005969
5970 /*
5971 * This routine is slightly over-complicated for
5972 * efficiency. Next we scan backwards looking for the
5973 * start of arithmetic.
5974 */
5975 start = stackblock();
5976 p = expdest - 1;
5977 *p = '\0';
5978 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005979 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005980 int esc;
5981
Denys Vlasenkocd716832009-11-28 22:14:02 +01005982 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005983 p--;
5984#if DEBUG
5985 if (p < start) {
5986 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5987 }
5988#endif
5989 }
5990
5991 esc = esclen(start, p);
5992 if (!(esc % 2)) {
5993 break;
5994 }
5995
5996 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005997 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005998
5999 begoff = p - start;
6000
6001 removerecordregions(begoff);
6002
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006003 expdest = p;
6004
Ron Yorston549deab2015-05-18 09:57:51 +02006005 if (flag & QUOTES_ESC)
6006 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006007
Ron Yorston549deab2015-05-18 09:57:51 +02006008 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006009
Ron Yorston549deab2015-05-18 09:57:51 +02006010 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006011 recordregion(begoff, begoff + len, 0);
6012}
6013#endif
6014
6015/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006016static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006017
6018/*
6019 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6020 * characters to allow for further processing. Otherwise treat
6021 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006022 *
6023 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6024 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6025 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006026 */
6027static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006028argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006029{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006030 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006031 '=',
6032 ':',
6033 CTLQUOTEMARK,
6034 CTLENDVAR,
6035 CTLESC,
6036 CTLVAR,
6037 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006038#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006039 CTLENDARI,
6040#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006041 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006042 };
6043 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006044 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006045 int inquotes;
6046 size_t length;
6047 int startloc;
6048
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006049 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006050 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006051 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006052 reject++;
6053 }
6054 inquotes = 0;
6055 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006056 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006057 char *q;
6058
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006059 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006060 tilde:
6061 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006062 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006063 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006064 }
6065 start:
6066 startloc = expdest - (char *)stackblock();
6067 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006068 unsigned char c;
6069
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006070 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006071 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006072 if (c) {
6073 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006074 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006075 ) {
6076 /* c == '=' || c == ':' || c == CTLENDARI */
6077 length++;
6078 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006079 }
6080 if (length > 0) {
6081 int newloc;
6082 expdest = stack_nputstr(p, length, expdest);
6083 newloc = expdest - (char *)stackblock();
6084 if (breakall && !inquotes && newloc > startloc) {
6085 recordregion(startloc, newloc, 0);
6086 }
6087 startloc = newloc;
6088 }
6089 p += length + 1;
6090 length = 0;
6091
6092 switch (c) {
6093 case '\0':
6094 goto breakloop;
6095 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006096 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006097 p--;
6098 continue;
6099 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006100 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006101 reject++;
6102 /* fall through */
6103 case ':':
6104 /*
6105 * sort of a hack - expand tildes in variable
6106 * assignments (after the first '=' and after ':'s).
6107 */
6108 if (*--p == '~') {
6109 goto tilde;
6110 }
6111 continue;
6112 }
6113
6114 switch (c) {
6115 case CTLENDVAR: /* ??? */
6116 goto breakloop;
6117 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006118 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006119 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006120 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6121 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006122 goto start;
6123 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006124 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006125 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006126 p--;
6127 length++;
6128 startloc++;
6129 }
6130 break;
6131 case CTLESC:
6132 startloc++;
6133 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006134
6135 /*
6136 * Quoted parameter expansion pattern: remove quote
6137 * unless inside inner quotes or we have a literal
6138 * backslash.
6139 */
6140 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6141 EXP_QPAT && *p != '\\')
6142 break;
6143
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006144 goto addquote;
6145 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006146 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006147 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006148 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006149 goto start;
6150 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006151 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006152 argbackq = argbackq->next;
6153 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006154#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006155 case CTLENDARI:
6156 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006157 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006158 goto start;
6159#endif
6160 }
6161 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006162 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006163}
6164
6165static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006166scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6167 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006168{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006169 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006170 char c;
6171
6172 loc = startp;
6173 loc2 = rmesc;
6174 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006175 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006176 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006177
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006178 c = *loc2;
6179 if (zero) {
6180 *loc2 = '\0';
6181 s = rmesc;
6182 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006183 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006184
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006185 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006186 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006187 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006188 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006189 loc++;
6190 loc++;
6191 loc2++;
6192 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006193 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006194}
6195
6196static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006197scanright(char *startp, char *rmesc, char *rmescend,
6198 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006199{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006200#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6201 int try2optimize = match_at_start;
6202#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006203 int esc = 0;
6204 char *loc;
6205 char *loc2;
6206
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006207 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6208 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6209 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6210 * Logic:
6211 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6212 * and on each iteration they go back two/one char until they reach the beginning.
6213 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6214 */
6215 /* TODO: document in what other circumstances we are called. */
6216
6217 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006218 int match;
6219 char c = *loc2;
6220 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006221 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006222 *loc2 = '\0';
6223 s = rmesc;
6224 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006225 match = pmatch(pattern, s);
6226 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006227 *loc2 = c;
6228 if (match)
6229 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006230#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6231 if (try2optimize) {
6232 /* Maybe we can optimize this:
6233 * if pattern ends with unescaped *, we can avoid checking
6234 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6235 * it wont match truncated "raw_value_of_" strings too.
6236 */
6237 unsigned plen = strlen(pattern);
6238 /* Does it end with "*"? */
6239 if (plen != 0 && pattern[--plen] == '*') {
6240 /* "xxxx*" is not escaped */
6241 /* "xxx\*" is escaped */
6242 /* "xx\\*" is not escaped */
6243 /* "x\\\*" is escaped */
6244 int slashes = 0;
6245 while (plen != 0 && pattern[--plen] == '\\')
6246 slashes++;
6247 if (!(slashes & 1))
6248 break; /* ends with unescaped "*" */
6249 }
6250 try2optimize = 0;
6251 }
6252#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006253 loc--;
6254 if (quotes) {
6255 if (--esc < 0) {
6256 esc = esclen(startp, loc);
6257 }
6258 if (esc % 2) {
6259 esc--;
6260 loc--;
6261 }
6262 }
6263 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006264 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265}
6266
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006267static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006268static void
6269varunset(const char *end, const char *var, const char *umsg, int varflags)
6270{
6271 const char *msg;
6272 const char *tail;
6273
6274 tail = nullstr;
6275 msg = "parameter not set";
6276 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006277 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006278 if (varflags & VSNUL)
6279 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006280 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006281 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006282 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006283 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006284 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006285}
6286
6287static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006288subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006289 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006290{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006291 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006292 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006293 char *startp;
6294 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006295 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006296 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006297 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006298 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006299 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006300 int amount, resetloc;
6301 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006302 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006303 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006304
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006305 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6306 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006307
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006308 herefd = -1;
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006309 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006310 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6311 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006312 STPUTC('\0', expdest);
6313 herefd = saveherefd;
6314 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006315 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006316
6317 switch (subtype) {
6318 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006319 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006320 amount = startp - expdest;
6321 STADJUST(amount, expdest);
6322 return startp;
6323
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006324 case VSQUESTION:
6325 varunset(p, varname, startp, varflags);
6326 /* NOTREACHED */
6327
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006328#if ENABLE_ASH_BASH_COMPAT
6329 case VSSUBSTR:
6330 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006331 /* Read POS in ${var:POS:LEN} */
6332 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006333 len = str - startp - 1;
6334
6335 /* *loc != '\0', guaranteed by parser */
6336 if (quotes) {
6337 char *ptr;
6338
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006339 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006340 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006341 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006342 len--;
6343 ptr++;
6344 }
6345 }
6346 }
6347 orig_len = len;
6348
6349 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006350 /* ${var::LEN} */
6351 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006352 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006353 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006354 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006355 while (*loc && *loc != ':') {
6356 /* TODO?
6357 * bash complains on: var=qwe; echo ${var:1a:123}
6358 if (!isdigit(*loc))
6359 ash_msg_and_raise_error(msg_illnum, str);
6360 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006361 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006362 }
6363 if (*loc++ == ':') {
6364 len = number(loc);
6365 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006366 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006367 if (pos < 0) {
6368 /* ${VAR:$((-n)):l} starts n chars from the end */
6369 pos = orig_len + pos;
6370 }
6371 if ((unsigned)pos >= orig_len) {
6372 /* apart from obvious ${VAR:999999:l},
6373 * covers ${VAR:$((-9999999)):l} - result is ""
6374 * (bash-compat)
6375 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006376 pos = 0;
6377 len = 0;
6378 }
6379 if (len > (orig_len - pos))
6380 len = orig_len - pos;
6381
6382 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006383 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006384 str++;
6385 }
6386 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006387 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006388 *loc++ = *str++;
6389 *loc++ = *str++;
6390 }
6391 *loc = '\0';
6392 amount = loc - expdest;
6393 STADJUST(amount, expdest);
6394 return loc;
6395#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006396 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006397
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006398 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006399
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006400 /* We'll comeback here if we grow the stack while handling
6401 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6402 * stack will need rebasing, and we'll need to remove our work
6403 * areas each time
6404 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006405 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006406
6407 amount = expdest - ((char *)stackblock() + resetloc);
6408 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006409 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006410
6411 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006412 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006413 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006414 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006415 if (rmesc != startp) {
6416 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006417 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006418 }
6419 }
6420 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006421 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006422 /*
6423 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6424 * The result is a_\_z_c (not a\_\_z_c)!
6425 *
6426 * The search pattern and replace string treat backslashes differently!
6427 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6428 * and string. It's only used on the first call.
6429 */
6430 preglob(str, IF_ASH_BASH_COMPAT(
6431 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6432 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006433
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006434#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006435 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006436 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006437 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006438
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006439 if (!repl) {
Ron Yorston417622c2015-05-18 09:59:14 +02006440 if ((repl=strchr(str, CTLESC)))
6441 *repl++ = '\0';
6442 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006443 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006444 }
Ron Yorston417622c2015-05-18 09:59:14 +02006445 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006446
6447 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006448 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006449 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006450
6451 len = 0;
6452 idx = startp;
6453 end = str - 1;
6454 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006455 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006456 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006457 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006458 if (!loc) {
6459 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006460 char *restart_detect = stackblock();
6461 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006462 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006463 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006464 idx++;
6465 len++;
6466 STPUTC(*idx, expdest);
6467 }
6468 if (stackblock() != restart_detect)
6469 goto restart;
6470 idx++;
6471 len++;
6472 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006473 /* continue; - prone to quadratic behavior, smarter code: */
6474 if (idx >= end)
6475 break;
6476 if (str[0] == '*') {
6477 /* Pattern is "*foo". If "*foo" does not match "long_string",
6478 * it would never match "ong_string" etc, no point in trying.
6479 */
6480 goto skip_matching;
6481 }
6482 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006483 }
6484
6485 if (subtype == VSREPLACEALL) {
6486 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006487 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006488 idx++;
6489 idx++;
6490 rmesc++;
6491 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006492 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006493 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006494 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006495
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006496 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006497 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006498 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006499 if (quotes && *loc == '\\') {
6500 STPUTC(CTLESC, expdest);
6501 len++;
6502 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006503 STPUTC(*loc, expdest);
6504 if (stackblock() != restart_detect)
6505 goto restart;
6506 len++;
6507 }
6508
6509 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006510 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006511 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006512 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006513 STPUTC(*idx, expdest);
6514 if (stackblock() != restart_detect)
6515 goto restart;
6516 len++;
6517 idx++;
6518 }
6519 break;
6520 }
6521 }
6522
6523 /* We've put the replaced text into a buffer at workloc, now
6524 * move it to the right place and adjust the stack.
6525 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006526 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006527 startp = (char *)stackblock() + startloc;
6528 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006529 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006530 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006531 STADJUST(-amount, expdest);
6532 return startp;
6533 }
6534#endif /* ENABLE_ASH_BASH_COMPAT */
6535
6536 subtype -= VSTRIMRIGHT;
6537#if DEBUG
6538 if (subtype < 0 || subtype > 7)
6539 abort();
6540#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006541 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006542 zero = subtype >> 1;
6543 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6544 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6545
6546 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6547 if (loc) {
6548 if (zero) {
6549 memmove(startp, loc, str - loc);
6550 loc = startp + (str - loc) - 1;
6551 }
6552 *loc = '\0';
6553 amount = loc - expdest;
6554 STADJUST(amount, expdest);
6555 }
6556 return loc;
6557}
6558
6559/*
6560 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006561 * name parameter (examples):
6562 * ash -c 'echo $1' name:'1='
6563 * ash -c 'echo $qwe' name:'qwe='
6564 * ash -c 'echo $$' name:'$='
6565 * ash -c 'echo ${$}' name:'$='
6566 * ash -c 'echo ${$##q}' name:'$=q'
6567 * ash -c 'echo ${#$}' name:'$='
6568 * note: examples with bad shell syntax:
6569 * ash -c 'echo ${#$1}' name:'$=1'
6570 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006571 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006572static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006573varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006574{
Mike Frysinger98c52642009-04-02 10:02:37 +00006575 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006576 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006577 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006578 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006579 int sep;
Ron Yorston549deab2015-05-18 09:57:51 +02006580 int quoted = flags & EXP_QUOTED;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006581 int subtype = varflags & VSTYPE;
6582 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6583 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006584 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006585
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006586 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
6587
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006588 switch (*name) {
6589 case '$':
6590 num = rootpid;
6591 goto numvar;
6592 case '?':
6593 num = exitstatus;
6594 goto numvar;
6595 case '#':
6596 num = shellparam.nparam;
6597 goto numvar;
6598 case '!':
6599 num = backgndpid;
6600 if (num == 0)
6601 return -1;
6602 numvar:
6603 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006604 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006605 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006606 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607 for (i = NOPTS - 1; i >= 0; i--) {
6608 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006609 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006610 len++;
6611 }
6612 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006613 check_1char_name:
6614#if 0
6615 /* handles cases similar to ${#$1} */
6616 if (name[2] != '\0')
6617 raise_error_syntax("bad substitution");
6618#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006619 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006620 case '@': {
6621 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006622 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006623
6624 if (quoted && (flags & EXP_FULL)) {
6625 /* note: this is not meant as PEOF value */
6626 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006627 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006628 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006629 /* fall through */
6630 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006631 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006632 param:
6633 ap = shellparam.p;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006634 sepc = sep;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006635 if (!ap)
6636 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006637 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006638 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006639
6640 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006641 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006642 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006643 }
6644 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006645 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006646 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006647 case '0':
6648 case '1':
6649 case '2':
6650 case '3':
6651 case '4':
6652 case '5':
6653 case '6':
6654 case '7':
6655 case '8':
6656 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006657 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006658 if (num < 0 || num > shellparam.nparam)
6659 return -1;
6660 p = num ? shellparam.p[num - 1] : arg0;
6661 goto value;
6662 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006663 /* NB: name has form "VAR=..." */
6664
6665 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6666 * which should be considered before we check variables. */
6667 if (var_str_list) {
6668 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6669 p = NULL;
6670 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006671 char *str, *eq;
6672 str = var_str_list->text;
6673 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006674 if (!eq) /* stop at first non-assignment */
6675 break;
6676 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006677 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006678 && strncmp(str, name, name_len) == 0
6679 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006680 p = eq;
6681 /* goto value; - WRONG! */
6682 /* think "A=1 A=2 B=$A" */
6683 }
6684 var_str_list = var_str_list->next;
6685 } while (var_str_list);
6686 if (p)
6687 goto value;
6688 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006689 p = lookupvar(name);
6690 value:
6691 if (!p)
6692 return -1;
6693
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006694 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006695#if ENABLE_UNICODE_SUPPORT
6696 if (subtype == VSLENGTH && len > 0) {
6697 reinit_unicode_for_ash();
6698 if (unicode_status == UNICODE_ON) {
6699 len = unicode_strlen(p);
6700 }
6701 }
6702#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006703 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006704 }
6705
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006706 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006707 STADJUST(-len, expdest);
6708 return len;
6709}
6710
6711/*
6712 * Expand a variable, and return a pointer to the next character in the
6713 * input string.
6714 */
6715static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006716evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006717{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006718 char varflags;
6719 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006720 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006721 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006722 char *var;
6723 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006724 int startloc;
6725 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006726
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006727 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006728 subtype = varflags & VSTYPE;
Ron Yorston549deab2015-05-18 09:57:51 +02006729 quoted = flags & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006730 var = p;
6731 easy = (!quoted || (*var == '@' && shellparam.nparam));
6732 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006733 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006734
6735 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006736 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006737 if (varflags & VSNUL)
6738 varlen--;
6739
6740 if (subtype == VSPLUS) {
6741 varlen = -1 - varlen;
6742 goto vsplus;
6743 }
6744
6745 if (subtype == VSMINUS) {
6746 vsplus:
6747 if (varlen < 0) {
6748 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006749 p,
Ron Yorston549deab2015-05-18 09:57:51 +02006750 flags | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006751 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006752 );
6753 goto end;
6754 }
6755 if (easy)
6756 goto record;
6757 goto end;
6758 }
6759
6760 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6761 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006762 if (subevalvar(p, var, /* strloc: */ 0,
6763 subtype, startloc, varflags,
Ron Yorston549deab2015-05-18 09:57:51 +02006764 /* quotes: */ flags & ~QUOTES_ESC,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006765 var_str_list)
6766 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006767 varflags &= ~VSNUL;
6768 /*
6769 * Remove any recorded regions beyond
6770 * start of variable
6771 */
6772 removerecordregions(startloc);
6773 goto again;
6774 }
6775 goto end;
6776 }
6777 if (easy)
6778 goto record;
6779 goto end;
6780 }
6781
6782 if (varlen < 0 && uflag)
6783 varunset(p, var, 0, 0);
6784
6785 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006786 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006787 goto record;
6788 }
6789
6790 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006791 if (easy)
6792 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006793 goto end;
6794 }
6795
6796#if DEBUG
6797 switch (subtype) {
6798 case VSTRIMLEFT:
6799 case VSTRIMLEFTMAX:
6800 case VSTRIMRIGHT:
6801 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006802#if ENABLE_ASH_BASH_COMPAT
6803 case VSSUBSTR:
6804 case VSREPLACE:
6805 case VSREPLACEALL:
6806#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006807 break;
6808 default:
6809 abort();
6810 }
6811#endif
6812
6813 if (varlen >= 0) {
6814 /*
6815 * Terminate the string and start recording the pattern
6816 * right after it
6817 */
6818 STPUTC('\0', expdest);
6819 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006820 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006821 startloc, varflags, flags, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006822 int amount = expdest - (
6823 (char *)stackblock() + patloc - 1
6824 );
6825 STADJUST(-amount, expdest);
6826 }
6827 /* Remove any recorded regions beyond start of variable */
6828 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006829 record:
6830 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006831 }
6832
6833 end:
6834 if (subtype != VSNORMAL) { /* skip to end of alternative */
6835 int nesting = 1;
6836 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006837 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006838 if (c == CTLESC)
6839 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006840 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006841 if (varlen >= 0)
6842 argbackq = argbackq->next;
6843 } else if (c == CTLVAR) {
6844 if ((*p++ & VSTYPE) != VSNORMAL)
6845 nesting++;
6846 } else if (c == CTLENDVAR) {
6847 if (--nesting == 0)
6848 break;
6849 }
6850 }
6851 }
6852 return p;
6853}
6854
6855/*
6856 * Break the argument string into pieces based upon IFS and add the
6857 * strings to the argument list. The regions of the string to be
6858 * searched for IFS characters have been stored by recordregion.
6859 */
6860static void
6861ifsbreakup(char *string, struct arglist *arglist)
6862{
6863 struct ifsregion *ifsp;
6864 struct strlist *sp;
6865 char *start;
6866 char *p;
6867 char *q;
6868 const char *ifs, *realifs;
6869 int ifsspc;
6870 int nulonly;
6871
6872 start = string;
6873 if (ifslastp != NULL) {
6874 ifsspc = 0;
6875 nulonly = 0;
6876 realifs = ifsset() ? ifsval() : defifs;
6877 ifsp = &ifsfirst;
6878 do {
6879 p = string + ifsp->begoff;
6880 nulonly = ifsp->nulonly;
6881 ifs = nulonly ? nullstr : realifs;
6882 ifsspc = 0;
6883 while (p < string + ifsp->endoff) {
6884 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006885 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006886 p++;
6887 if (!strchr(ifs, *p)) {
6888 p++;
6889 continue;
6890 }
6891 if (!nulonly)
6892 ifsspc = (strchr(defifs, *p) != NULL);
6893 /* Ignore IFS whitespace at start */
6894 if (q == start && ifsspc) {
6895 p++;
6896 start = p;
6897 continue;
6898 }
6899 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006900 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006901 sp->text = start;
6902 *arglist->lastp = sp;
6903 arglist->lastp = &sp->next;
6904 p++;
6905 if (!nulonly) {
6906 for (;;) {
6907 if (p >= string + ifsp->endoff) {
6908 break;
6909 }
6910 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006911 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006912 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006913 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006914 p = q;
6915 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006916 }
6917 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006918 if (ifsspc) {
6919 p++;
6920 ifsspc = 0;
6921 } else {
6922 p = q;
6923 break;
6924 }
6925 } else
6926 p++;
6927 }
6928 }
6929 start = p;
6930 } /* while */
6931 ifsp = ifsp->next;
6932 } while (ifsp != NULL);
6933 if (nulonly)
6934 goto add;
6935 }
6936
6937 if (!*start)
6938 return;
6939
6940 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006941 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006942 sp->text = start;
6943 *arglist->lastp = sp;
6944 arglist->lastp = &sp->next;
6945}
6946
6947static void
6948ifsfree(void)
6949{
6950 struct ifsregion *p;
6951
6952 INT_OFF;
6953 p = ifsfirst.next;
6954 do {
6955 struct ifsregion *ifsp;
6956 ifsp = p->next;
6957 free(p);
6958 p = ifsp;
6959 } while (p);
6960 ifslastp = NULL;
6961 ifsfirst.next = NULL;
6962 INT_ON;
6963}
6964
6965/*
6966 * Add a file name to the list.
6967 */
6968static void
6969addfname(const char *name)
6970{
6971 struct strlist *sp;
6972
Denis Vlasenko597906c2008-02-20 16:38:54 +00006973 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006974 sp->text = ststrdup(name);
6975 *exparg.lastp = sp;
6976 exparg.lastp = &sp->next;
6977}
6978
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006979/*
6980 * Do metacharacter (i.e. *, ?, [...]) expansion.
6981 */
6982static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006983expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006984{
6985 char *p;
6986 const char *cp;
6987 char *start;
6988 char *endname;
6989 int metaflag;
6990 struct stat statb;
6991 DIR *dirp;
6992 struct dirent *dp;
6993 int atend;
6994 int matchdot;
6995
6996 metaflag = 0;
6997 start = name;
6998 for (p = name; *p; p++) {
6999 if (*p == '*' || *p == '?')
7000 metaflag = 1;
7001 else if (*p == '[') {
7002 char *q = p + 1;
7003 if (*q == '!')
7004 q++;
7005 for (;;) {
7006 if (*q == '\\')
7007 q++;
7008 if (*q == '/' || *q == '\0')
7009 break;
7010 if (*++q == ']') {
7011 metaflag = 1;
7012 break;
7013 }
7014 }
7015 } else if (*p == '\\')
7016 p++;
7017 else if (*p == '/') {
7018 if (metaflag)
7019 goto out;
7020 start = p + 1;
7021 }
7022 }
7023 out:
7024 if (metaflag == 0) { /* we've reached the end of the file name */
7025 if (enddir != expdir)
7026 metaflag++;
7027 p = name;
7028 do {
7029 if (*p == '\\')
7030 p++;
7031 *enddir++ = *p;
7032 } while (*p++);
7033 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7034 addfname(expdir);
7035 return;
7036 }
7037 endname = p;
7038 if (name < start) {
7039 p = name;
7040 do {
7041 if (*p == '\\')
7042 p++;
7043 *enddir++ = *p++;
7044 } while (p < start);
7045 }
7046 if (enddir == expdir) {
7047 cp = ".";
7048 } else if (enddir == expdir + 1 && *expdir == '/') {
7049 cp = "/";
7050 } else {
7051 cp = expdir;
7052 enddir[-1] = '\0';
7053 }
7054 dirp = opendir(cp);
7055 if (dirp == NULL)
7056 return;
7057 if (enddir != expdir)
7058 enddir[-1] = '/';
7059 if (*endname == 0) {
7060 atend = 1;
7061 } else {
7062 atend = 0;
7063 *endname++ = '\0';
7064 }
7065 matchdot = 0;
7066 p = start;
7067 if (*p == '\\')
7068 p++;
7069 if (*p == '.')
7070 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007071 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007072 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007073 continue;
7074 if (pmatch(start, dp->d_name)) {
7075 if (atend) {
7076 strcpy(enddir, dp->d_name);
7077 addfname(expdir);
7078 } else {
7079 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7080 continue;
7081 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007082 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007083 }
7084 }
7085 }
7086 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007087 if (!atend)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007088 endname[-1] = '/';
7089}
7090
7091static struct strlist *
7092msort(struct strlist *list, int len)
7093{
7094 struct strlist *p, *q = NULL;
7095 struct strlist **lpp;
7096 int half;
7097 int n;
7098
7099 if (len <= 1)
7100 return list;
7101 half = len >> 1;
7102 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007103 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007104 q = p;
7105 p = p->next;
7106 }
7107 q->next = NULL; /* terminate first half of list */
7108 q = msort(list, half); /* sort first half of list */
7109 p = msort(p, len - half); /* sort second half */
7110 lpp = &list;
7111 for (;;) {
7112#if ENABLE_LOCALE_SUPPORT
7113 if (strcoll(p->text, q->text) < 0)
7114#else
7115 if (strcmp(p->text, q->text) < 0)
7116#endif
7117 {
7118 *lpp = p;
7119 lpp = &p->next;
7120 p = *lpp;
7121 if (p == NULL) {
7122 *lpp = q;
7123 break;
7124 }
7125 } else {
7126 *lpp = q;
7127 lpp = &q->next;
7128 q = *lpp;
7129 if (q == NULL) {
7130 *lpp = p;
7131 break;
7132 }
7133 }
7134 }
7135 return list;
7136}
7137
7138/*
7139 * Sort the results of file name expansion. It calculates the number of
7140 * strings to sort and then calls msort (short for merge sort) to do the
7141 * work.
7142 */
7143static struct strlist *
7144expsort(struct strlist *str)
7145{
7146 int len;
7147 struct strlist *sp;
7148
7149 len = 0;
7150 for (sp = str; sp; sp = sp->next)
7151 len++;
7152 return msort(str, len);
7153}
7154
7155static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007156expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007158 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007159 '*', '?', '[', 0
7160 };
7161 /* TODO - EXP_REDIR */
7162
7163 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007164 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007165 struct strlist **savelastp;
7166 struct strlist *sp;
7167 char *p;
7168
7169 if (fflag)
7170 goto nometa;
7171 if (!strpbrk(str->text, metachars))
7172 goto nometa;
7173 savelastp = exparg.lastp;
7174
7175 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007176 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007177 {
7178 int i = strlen(str->text);
7179 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7180 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007181 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007182 free(expdir);
7183 if (p != str->text)
7184 free(p);
7185 INT_ON;
7186 if (exparg.lastp == savelastp) {
7187 /*
7188 * no matches
7189 */
7190 nometa:
7191 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007192 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007193 exparg.lastp = &str->next;
7194 } else {
7195 *exparg.lastp = NULL;
7196 *savelastp = sp = expsort(*savelastp);
7197 while (sp->next != NULL)
7198 sp = sp->next;
7199 exparg.lastp = &sp->next;
7200 }
7201 str = str->next;
7202 }
7203}
7204
7205/*
7206 * Perform variable substitution and command substitution on an argument,
7207 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7208 * perform splitting and file name expansion. When arglist is NULL, perform
7209 * here document expansion.
7210 */
7211static void
7212expandarg(union node *arg, struct arglist *arglist, int flag)
7213{
7214 struct strlist *sp;
7215 char *p;
7216
7217 argbackq = arg->narg.backquote;
7218 STARTSTACKSTR(expdest);
7219 ifsfirst.next = NULL;
7220 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007221 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007222 argstr(arg->narg.text, flag,
7223 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007224 p = _STPUTC('\0', expdest);
7225 expdest = p - 1;
7226 if (arglist == NULL) {
7227 return; /* here document expanded */
7228 }
7229 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007230 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007231 exparg.lastp = &exparg.list;
7232 /*
7233 * TODO - EXP_REDIR
7234 */
7235 if (flag & EXP_FULL) {
7236 ifsbreakup(p, &exparg);
7237 *exparg.lastp = NULL;
7238 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007239 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007240 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007241 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007242 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007243 TRACE(("expandarg: rmescapes:'%s'\n", p));
7244 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007245 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007246 sp->text = p;
7247 *exparg.lastp = sp;
7248 exparg.lastp = &sp->next;
7249 }
7250 if (ifsfirst.next)
7251 ifsfree();
7252 *exparg.lastp = NULL;
7253 if (exparg.list) {
7254 *arglist->lastp = exparg.list;
7255 arglist->lastp = exparg.lastp;
7256 }
7257}
7258
7259/*
7260 * Expand shell variables and backquotes inside a here document.
7261 */
7262static void
7263expandhere(union node *arg, int fd)
7264{
7265 herefd = fd;
Ron Yorston549deab2015-05-18 09:57:51 +02007266 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007267 full_write(fd, stackblock(), expdest - (char *)stackblock());
7268}
7269
7270/*
7271 * Returns true if the pattern matches the string.
7272 */
7273static int
7274patmatch(char *pattern, const char *string)
7275{
Ron Yorston549deab2015-05-18 09:57:51 +02007276 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007277}
7278
7279/*
7280 * See if a pattern matches in a case statement.
7281 */
7282static int
7283casematch(union node *pattern, char *val)
7284{
7285 struct stackmark smark;
7286 int result;
7287
7288 setstackmark(&smark);
7289 argbackq = pattern->narg.backquote;
7290 STARTSTACKSTR(expdest);
7291 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007292 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7293 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007294 STACKSTRNUL(expdest);
7295 result = patmatch(stackblock(), val);
7296 popstackmark(&smark);
7297 return result;
7298}
7299
7300
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007301/* ============ find_command */
7302
7303struct builtincmd {
7304 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007305 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007306 /* unsigned flags; */
7307};
7308#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007309/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007310 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007311#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007312#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007313
7314struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007315 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007316 union param {
7317 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007318 /* index >= 0 for commands without path (slashes) */
7319 /* (TODO: what exactly does the value mean? PATH position?) */
7320 /* index == -1 for commands with slashes */
7321 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007322 const struct builtincmd *cmd;
7323 struct funcnode *func;
7324 } u;
7325};
7326/* values of cmdtype */
7327#define CMDUNKNOWN -1 /* no entry in table for command */
7328#define CMDNORMAL 0 /* command is an executable program */
7329#define CMDFUNCTION 1 /* command is a shell function */
7330#define CMDBUILTIN 2 /* command is a shell builtin */
7331
7332/* action to find_command() */
7333#define DO_ERR 0x01 /* prints errors */
7334#define DO_ABS 0x02 /* checks absolute paths */
7335#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7336#define DO_ALTPATH 0x08 /* using alternate path */
7337#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7338
7339static void find_command(char *, struct cmdentry *, int, const char *);
7340
7341
7342/* ============ Hashing commands */
7343
7344/*
7345 * When commands are first encountered, they are entered in a hash table.
7346 * This ensures that a full path search will not have to be done for them
7347 * on each invocation.
7348 *
7349 * We should investigate converting to a linear search, even though that
7350 * would make the command name "hash" a misnomer.
7351 */
7352
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007353struct tblentry {
7354 struct tblentry *next; /* next entry in hash chain */
7355 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007356 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007357 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007358 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007359};
7360
Denis Vlasenko01631112007-12-16 17:20:38 +00007361static struct tblentry **cmdtable;
7362#define INIT_G_cmdtable() do { \
7363 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7364} while (0)
7365
7366static int builtinloc = -1; /* index in path of %builtin, or -1 */
7367
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007368
7369static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007370tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007371{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007372#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007373 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007374 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007375 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007376 while (*envp)
7377 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007378 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007379 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007380 /* re-exec ourselves with the new arguments */
7381 execve(bb_busybox_exec_path, argv, envp);
7382 /* If they called chroot or otherwise made the binary no longer
7383 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007384 }
7385#endif
7386
7387 repeat:
7388#ifdef SYSV
7389 do {
7390 execve(cmd, argv, envp);
7391 } while (errno == EINTR);
7392#else
7393 execve(cmd, argv, envp);
7394#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007395 if (cmd == (char*) bb_busybox_exec_path) {
7396 /* We already visited ENOEXEC branch below, don't do it again */
7397//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007398 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007399 return;
7400 }
7401 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007402 /* Run "cmd" as a shell script:
7403 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7404 * "If the execve() function fails with ENOEXEC, the shell
7405 * shall execute a command equivalent to having a shell invoked
7406 * with the command name as its first operand,
7407 * with any remaining arguments passed to the new shell"
7408 *
7409 * That is, do not use $SHELL, user's shell, or /bin/sh;
7410 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007411 *
7412 * Note that bash reads ~80 chars of the file, and if it sees
7413 * a zero byte before it sees newline, it doesn't try to
7414 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007415 * message and exit code 126. For one, this prevents attempts
7416 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007417 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007418 char **ap;
7419 char **new;
7420
7421 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007422 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007423 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7424 new[0] = (char*) "ash";
7425 new[1] = cmd;
7426 ap = new + 2;
7427 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007428 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007429 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007430 argv = new;
7431 goto repeat;
7432 }
7433}
7434
7435/*
7436 * Exec a program. Never returns. If you change this routine, you may
7437 * have to change the find_command routine as well.
7438 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007439static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007440static void
7441shellexec(char **argv, const char *path, int idx)
7442{
7443 char *cmdname;
7444 int e;
7445 char **envp;
7446 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007447 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007448
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007449 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007450 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007451 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007452#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007453 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007454#endif
7455 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007456 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007457 if (applet_no >= 0) {
7458 /* We tried execing ourself, but it didn't work.
7459 * Maybe /proc/self/exe doesn't exist?
7460 * Try $PATH search.
7461 */
7462 goto try_PATH;
7463 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007464 e = errno;
7465 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007466 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007467 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007468 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007469 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007470 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007471 if (errno != ENOENT && errno != ENOTDIR)
7472 e = errno;
7473 }
7474 stunalloc(cmdname);
7475 }
7476 }
7477
7478 /* Map to POSIX errors */
7479 switch (e) {
7480 case EACCES:
7481 exerrno = 126;
7482 break;
7483 case ENOENT:
7484 exerrno = 127;
7485 break;
7486 default:
7487 exerrno = 2;
7488 break;
7489 }
7490 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007491 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7492 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007493 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7494 /* NOTREACHED */
7495}
7496
7497static void
7498printentry(struct tblentry *cmdp)
7499{
7500 int idx;
7501 const char *path;
7502 char *name;
7503
7504 idx = cmdp->param.index;
7505 path = pathval();
7506 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007507 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007508 stunalloc(name);
7509 } while (--idx >= 0);
7510 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7511}
7512
7513/*
7514 * Clear out command entries. The argument specifies the first entry in
7515 * PATH which has changed.
7516 */
7517static void
7518clearcmdentry(int firstchange)
7519{
7520 struct tblentry **tblp;
7521 struct tblentry **pp;
7522 struct tblentry *cmdp;
7523
7524 INT_OFF;
7525 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7526 pp = tblp;
7527 while ((cmdp = *pp) != NULL) {
7528 if ((cmdp->cmdtype == CMDNORMAL &&
7529 cmdp->param.index >= firstchange)
7530 || (cmdp->cmdtype == CMDBUILTIN &&
7531 builtinloc >= firstchange)
7532 ) {
7533 *pp = cmdp->next;
7534 free(cmdp);
7535 } else {
7536 pp = &cmdp->next;
7537 }
7538 }
7539 }
7540 INT_ON;
7541}
7542
7543/*
7544 * Locate a command in the command hash table. If "add" is nonzero,
7545 * add the command to the table if it is not already present. The
7546 * variable "lastcmdentry" is set to point to the address of the link
7547 * pointing to the entry, so that delete_cmd_entry can delete the
7548 * entry.
7549 *
7550 * Interrupts must be off if called with add != 0.
7551 */
7552static struct tblentry **lastcmdentry;
7553
7554static struct tblentry *
7555cmdlookup(const char *name, int add)
7556{
7557 unsigned int hashval;
7558 const char *p;
7559 struct tblentry *cmdp;
7560 struct tblentry **pp;
7561
7562 p = name;
7563 hashval = (unsigned char)*p << 4;
7564 while (*p)
7565 hashval += (unsigned char)*p++;
7566 hashval &= 0x7FFF;
7567 pp = &cmdtable[hashval % CMDTABLESIZE];
7568 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7569 if (strcmp(cmdp->cmdname, name) == 0)
7570 break;
7571 pp = &cmdp->next;
7572 }
7573 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007574 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7575 + strlen(name)
7576 /* + 1 - already done because
7577 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007578 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007579 cmdp->cmdtype = CMDUNKNOWN;
7580 strcpy(cmdp->cmdname, name);
7581 }
7582 lastcmdentry = pp;
7583 return cmdp;
7584}
7585
7586/*
7587 * Delete the command entry returned on the last lookup.
7588 */
7589static void
7590delete_cmd_entry(void)
7591{
7592 struct tblentry *cmdp;
7593
7594 INT_OFF;
7595 cmdp = *lastcmdentry;
7596 *lastcmdentry = cmdp->next;
7597 if (cmdp->cmdtype == CMDFUNCTION)
7598 freefunc(cmdp->param.func);
7599 free(cmdp);
7600 INT_ON;
7601}
7602
7603/*
7604 * Add a new command entry, replacing any existing command entry for
7605 * the same name - except special builtins.
7606 */
7607static void
7608addcmdentry(char *name, struct cmdentry *entry)
7609{
7610 struct tblentry *cmdp;
7611
7612 cmdp = cmdlookup(name, 1);
7613 if (cmdp->cmdtype == CMDFUNCTION) {
7614 freefunc(cmdp->param.func);
7615 }
7616 cmdp->cmdtype = entry->cmdtype;
7617 cmdp->param = entry->u;
7618 cmdp->rehash = 0;
7619}
7620
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007621static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007622hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007623{
7624 struct tblentry **pp;
7625 struct tblentry *cmdp;
7626 int c;
7627 struct cmdentry entry;
7628 char *name;
7629
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007630 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007631 clearcmdentry(0);
7632 return 0;
7633 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007634
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007635 if (*argptr == NULL) {
7636 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7637 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7638 if (cmdp->cmdtype == CMDNORMAL)
7639 printentry(cmdp);
7640 }
7641 }
7642 return 0;
7643 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007644
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007645 c = 0;
7646 while ((name = *argptr) != NULL) {
7647 cmdp = cmdlookup(name, 0);
7648 if (cmdp != NULL
7649 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007650 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7651 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007652 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007653 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007654 find_command(name, &entry, DO_ERR, pathval());
7655 if (entry.cmdtype == CMDUNKNOWN)
7656 c = 1;
7657 argptr++;
7658 }
7659 return c;
7660}
7661
7662/*
7663 * Called when a cd is done. Marks all commands so the next time they
7664 * are executed they will be rehashed.
7665 */
7666static void
7667hashcd(void)
7668{
7669 struct tblentry **pp;
7670 struct tblentry *cmdp;
7671
7672 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7673 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007674 if (cmdp->cmdtype == CMDNORMAL
7675 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007676 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007677 && builtinloc > 0)
7678 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007679 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007680 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007681 }
7682 }
7683}
7684
7685/*
7686 * Fix command hash table when PATH changed.
7687 * Called before PATH is changed. The argument is the new value of PATH;
7688 * pathval() still returns the old value at this point.
7689 * Called with interrupts off.
7690 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007691static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007692changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007693{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007694 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007695 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007696 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007697 int idx_bltin;
7698
7699 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007700 firstchange = 9999; /* assume no change */
7701 idx = 0;
7702 idx_bltin = -1;
7703 for (;;) {
7704 if (*old != *new) {
7705 firstchange = idx;
7706 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007707 || (*old == ':' && *new == '\0')
7708 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007709 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007710 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007711 old = new; /* ignore subsequent differences */
7712 }
7713 if (*new == '\0')
7714 break;
7715 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7716 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007717 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007718 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007719 new++;
7720 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007721 }
7722 if (builtinloc < 0 && idx_bltin >= 0)
7723 builtinloc = idx_bltin; /* zap builtins */
7724 if (builtinloc >= 0 && idx_bltin < 0)
7725 firstchange = 0;
7726 clearcmdentry(firstchange);
7727 builtinloc = idx_bltin;
7728}
7729
7730#define TEOF 0
7731#define TNL 1
7732#define TREDIR 2
7733#define TWORD 3
7734#define TSEMI 4
7735#define TBACKGND 5
7736#define TAND 6
7737#define TOR 7
7738#define TPIPE 8
7739#define TLP 9
7740#define TRP 10
7741#define TENDCASE 11
7742#define TENDBQUOTE 12
7743#define TNOT 13
7744#define TCASE 14
7745#define TDO 15
7746#define TDONE 16
7747#define TELIF 17
7748#define TELSE 18
7749#define TESAC 19
7750#define TFI 20
7751#define TFOR 21
7752#define TIF 22
7753#define TIN 23
7754#define TTHEN 24
7755#define TUNTIL 25
7756#define TWHILE 26
7757#define TBEGIN 27
7758#define TEND 28
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007759typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007760
7761/* first char is indicating which tokens mark the end of a list */
7762static const char *const tokname_array[] = {
7763 "\1end of file",
7764 "\0newline",
7765 "\0redirection",
7766 "\0word",
7767 "\0;",
7768 "\0&",
7769 "\0&&",
7770 "\0||",
7771 "\0|",
7772 "\0(",
7773 "\1)",
7774 "\1;;",
7775 "\1`",
7776#define KWDOFFSET 13
7777 /* the following are keywords */
7778 "\0!",
7779 "\0case",
7780 "\1do",
7781 "\1done",
7782 "\1elif",
7783 "\1else",
7784 "\1esac",
7785 "\1fi",
7786 "\0for",
7787 "\0if",
7788 "\0in",
7789 "\1then",
7790 "\0until",
7791 "\0while",
7792 "\0{",
7793 "\1}",
7794};
7795
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007796/* Wrapper around strcmp for qsort/bsearch/... */
7797static int
7798pstrcmp(const void *a, const void *b)
7799{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007800 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007801}
7802
7803static const char *const *
7804findkwd(const char *s)
7805{
7806 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007807 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7808 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007809}
7810
7811/*
7812 * Locate and print what a word is...
7813 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007814static int
7815describe_command(char *command, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007816{
7817 struct cmdentry entry;
7818 struct tblentry *cmdp;
7819#if ENABLE_ASH_ALIAS
7820 const struct alias *ap;
7821#endif
7822 const char *path = pathval();
7823
7824 if (describe_command_verbose) {
7825 out1str(command);
7826 }
7827
7828 /* First look at the keywords */
7829 if (findkwd(command)) {
7830 out1str(describe_command_verbose ? " is a shell keyword" : command);
7831 goto out;
7832 }
7833
7834#if ENABLE_ASH_ALIAS
7835 /* Then look at the aliases */
7836 ap = lookupalias(command, 0);
7837 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007838 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007839 out1str("alias ");
7840 printalias(ap);
7841 return 0;
7842 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007843 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007844 goto out;
7845 }
7846#endif
7847 /* Then check if it is a tracked alias */
7848 cmdp = cmdlookup(command, 0);
7849 if (cmdp != NULL) {
7850 entry.cmdtype = cmdp->cmdtype;
7851 entry.u = cmdp->param;
7852 } else {
7853 /* Finally use brute force */
7854 find_command(command, &entry, DO_ABS, path);
7855 }
7856
7857 switch (entry.cmdtype) {
7858 case CMDNORMAL: {
7859 int j = entry.u.index;
7860 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007861 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007862 p = command;
7863 } else {
7864 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007865 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007866 stunalloc(p);
7867 } while (--j >= 0);
7868 }
7869 if (describe_command_verbose) {
7870 out1fmt(" is%s %s",
7871 (cmdp ? " a tracked alias for" : nullstr), p
7872 );
7873 } else {
7874 out1str(p);
7875 }
7876 break;
7877 }
7878
7879 case CMDFUNCTION:
7880 if (describe_command_verbose) {
7881 out1str(" is a shell function");
7882 } else {
7883 out1str(command);
7884 }
7885 break;
7886
7887 case CMDBUILTIN:
7888 if (describe_command_verbose) {
7889 out1fmt(" is a %sshell builtin",
7890 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7891 "special " : nullstr
7892 );
7893 } else {
7894 out1str(command);
7895 }
7896 break;
7897
7898 default:
7899 if (describe_command_verbose) {
7900 out1str(": not found\n");
7901 }
7902 return 127;
7903 }
7904 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01007905 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007906 return 0;
7907}
7908
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007909static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007910typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007911{
Denis Vlasenko46846e22007-05-20 13:08:31 +00007912 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007913 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00007914 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007915
Denis Vlasenko46846e22007-05-20 13:08:31 +00007916 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00007917 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007918 i++;
7919 verbose = 0;
7920 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00007921 while (argv[i]) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007922 err |= describe_command(argv[i++], verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007923 }
7924 return err;
7925}
7926
7927#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007928static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007929commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007930{
7931 int c;
7932 enum {
7933 VERIFY_BRIEF = 1,
7934 VERIFY_VERBOSE = 2,
7935 } verify = 0;
7936
7937 while ((c = nextopt("pvV")) != '\0')
7938 if (c == 'V')
7939 verify |= VERIFY_VERBOSE;
7940 else if (c == 'v')
7941 verify |= VERIFY_BRIEF;
7942#if DEBUG
7943 else if (c != 'p')
7944 abort();
7945#endif
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007946 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7947 if (verify && (*argptr != NULL)) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007948 return describe_command(*argptr, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007949 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007950
7951 return 0;
7952}
7953#endif
7954
7955
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007956/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00007957
Denis Vlasenko340299a2008-11-21 10:36:36 +00007958static int funcblocksize; /* size of structures in function */
7959static int funcstringsize; /* size of strings in node */
7960static void *funcblock; /* block to allocate function from */
7961static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007962
Eric Andersencb57d552001-06-28 07:25:16 +00007963/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00007964#define EV_EXIT 01 /* exit after evaluating tree */
7965#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersenc470f442003-07-28 09:56:35 +00007966#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00007967
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02007968static const uint8_t nodesize[N_NUMBER] = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00007969 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
7970 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
7971 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
7972 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7973 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7974 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
7975 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
7976 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
7977 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
7978 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
7979 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
7980 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
7981 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
7982 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
7983 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
7984 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
7985 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00007986#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00007987 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00007988#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00007989 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7990 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
7991 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7992 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
7993 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7994 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7995 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7996 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
7997 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007998};
7999
8000static void calcsize(union node *n);
8001
8002static void
8003sizenodelist(struct nodelist *lp)
8004{
8005 while (lp) {
8006 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8007 calcsize(lp->n);
8008 lp = lp->next;
8009 }
8010}
8011
8012static void
8013calcsize(union node *n)
8014{
8015 if (n == NULL)
8016 return;
8017 funcblocksize += nodesize[n->type];
8018 switch (n->type) {
8019 case NCMD:
8020 calcsize(n->ncmd.redirect);
8021 calcsize(n->ncmd.args);
8022 calcsize(n->ncmd.assign);
8023 break;
8024 case NPIPE:
8025 sizenodelist(n->npipe.cmdlist);
8026 break;
8027 case NREDIR:
8028 case NBACKGND:
8029 case NSUBSHELL:
8030 calcsize(n->nredir.redirect);
8031 calcsize(n->nredir.n);
8032 break;
8033 case NAND:
8034 case NOR:
8035 case NSEMI:
8036 case NWHILE:
8037 case NUNTIL:
8038 calcsize(n->nbinary.ch2);
8039 calcsize(n->nbinary.ch1);
8040 break;
8041 case NIF:
8042 calcsize(n->nif.elsepart);
8043 calcsize(n->nif.ifpart);
8044 calcsize(n->nif.test);
8045 break;
8046 case NFOR:
8047 funcstringsize += strlen(n->nfor.var) + 1;
8048 calcsize(n->nfor.body);
8049 calcsize(n->nfor.args);
8050 break;
8051 case NCASE:
8052 calcsize(n->ncase.cases);
8053 calcsize(n->ncase.expr);
8054 break;
8055 case NCLIST:
8056 calcsize(n->nclist.body);
8057 calcsize(n->nclist.pattern);
8058 calcsize(n->nclist.next);
8059 break;
8060 case NDEFUN:
8061 case NARG:
8062 sizenodelist(n->narg.backquote);
8063 funcstringsize += strlen(n->narg.text) + 1;
8064 calcsize(n->narg.next);
8065 break;
8066 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008067#if ENABLE_ASH_BASH_COMPAT
8068 case NTO2:
8069#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008070 case NCLOBBER:
8071 case NFROM:
8072 case NFROMTO:
8073 case NAPPEND:
8074 calcsize(n->nfile.fname);
8075 calcsize(n->nfile.next);
8076 break;
8077 case NTOFD:
8078 case NFROMFD:
8079 calcsize(n->ndup.vname);
8080 calcsize(n->ndup.next);
8081 break;
8082 case NHERE:
8083 case NXHERE:
8084 calcsize(n->nhere.doc);
8085 calcsize(n->nhere.next);
8086 break;
8087 case NNOT:
8088 calcsize(n->nnot.com);
8089 break;
8090 };
8091}
8092
8093static char *
8094nodeckstrdup(char *s)
8095{
8096 char *rtn = funcstring;
8097
8098 strcpy(funcstring, s);
8099 funcstring += strlen(s) + 1;
8100 return rtn;
8101}
8102
8103static union node *copynode(union node *);
8104
8105static struct nodelist *
8106copynodelist(struct nodelist *lp)
8107{
8108 struct nodelist *start;
8109 struct nodelist **lpp;
8110
8111 lpp = &start;
8112 while (lp) {
8113 *lpp = funcblock;
8114 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8115 (*lpp)->n = copynode(lp->n);
8116 lp = lp->next;
8117 lpp = &(*lpp)->next;
8118 }
8119 *lpp = NULL;
8120 return start;
8121}
8122
8123static union node *
8124copynode(union node *n)
8125{
8126 union node *new;
8127
8128 if (n == NULL)
8129 return NULL;
8130 new = funcblock;
8131 funcblock = (char *) funcblock + nodesize[n->type];
8132
8133 switch (n->type) {
8134 case NCMD:
8135 new->ncmd.redirect = copynode(n->ncmd.redirect);
8136 new->ncmd.args = copynode(n->ncmd.args);
8137 new->ncmd.assign = copynode(n->ncmd.assign);
8138 break;
8139 case NPIPE:
8140 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008141 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008142 break;
8143 case NREDIR:
8144 case NBACKGND:
8145 case NSUBSHELL:
8146 new->nredir.redirect = copynode(n->nredir.redirect);
8147 new->nredir.n = copynode(n->nredir.n);
8148 break;
8149 case NAND:
8150 case NOR:
8151 case NSEMI:
8152 case NWHILE:
8153 case NUNTIL:
8154 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8155 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8156 break;
8157 case NIF:
8158 new->nif.elsepart = copynode(n->nif.elsepart);
8159 new->nif.ifpart = copynode(n->nif.ifpart);
8160 new->nif.test = copynode(n->nif.test);
8161 break;
8162 case NFOR:
8163 new->nfor.var = nodeckstrdup(n->nfor.var);
8164 new->nfor.body = copynode(n->nfor.body);
8165 new->nfor.args = copynode(n->nfor.args);
8166 break;
8167 case NCASE:
8168 new->ncase.cases = copynode(n->ncase.cases);
8169 new->ncase.expr = copynode(n->ncase.expr);
8170 break;
8171 case NCLIST:
8172 new->nclist.body = copynode(n->nclist.body);
8173 new->nclist.pattern = copynode(n->nclist.pattern);
8174 new->nclist.next = copynode(n->nclist.next);
8175 break;
8176 case NDEFUN:
8177 case NARG:
8178 new->narg.backquote = copynodelist(n->narg.backquote);
8179 new->narg.text = nodeckstrdup(n->narg.text);
8180 new->narg.next = copynode(n->narg.next);
8181 break;
8182 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008183#if ENABLE_ASH_BASH_COMPAT
8184 case NTO2:
8185#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008186 case NCLOBBER:
8187 case NFROM:
8188 case NFROMTO:
8189 case NAPPEND:
8190 new->nfile.fname = copynode(n->nfile.fname);
8191 new->nfile.fd = n->nfile.fd;
8192 new->nfile.next = copynode(n->nfile.next);
8193 break;
8194 case NTOFD:
8195 case NFROMFD:
8196 new->ndup.vname = copynode(n->ndup.vname);
8197 new->ndup.dupfd = n->ndup.dupfd;
8198 new->ndup.fd = n->ndup.fd;
8199 new->ndup.next = copynode(n->ndup.next);
8200 break;
8201 case NHERE:
8202 case NXHERE:
8203 new->nhere.doc = copynode(n->nhere.doc);
8204 new->nhere.fd = n->nhere.fd;
8205 new->nhere.next = copynode(n->nhere.next);
8206 break;
8207 case NNOT:
8208 new->nnot.com = copynode(n->nnot.com);
8209 break;
8210 };
8211 new->type = n->type;
8212 return new;
8213}
8214
8215/*
8216 * Make a copy of a parse tree.
8217 */
8218static struct funcnode *
8219copyfunc(union node *n)
8220{
8221 struct funcnode *f;
8222 size_t blocksize;
8223
8224 funcblocksize = offsetof(struct funcnode, n);
8225 funcstringsize = 0;
8226 calcsize(n);
8227 blocksize = funcblocksize;
8228 f = ckmalloc(blocksize + funcstringsize);
8229 funcblock = (char *) f + offsetof(struct funcnode, n);
8230 funcstring = (char *) f + blocksize;
8231 copynode(n);
8232 f->count = 0;
8233 return f;
8234}
8235
8236/*
8237 * Define a shell function.
8238 */
8239static void
8240defun(char *name, union node *func)
8241{
8242 struct cmdentry entry;
8243
8244 INT_OFF;
8245 entry.cmdtype = CMDFUNCTION;
8246 entry.u.func = copyfunc(func);
8247 addcmdentry(name, &entry);
8248 INT_ON;
8249}
8250
Denis Vlasenko4b875702009-03-19 13:30:04 +00008251/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008252#define SKIPBREAK (1 << 0)
8253#define SKIPCONT (1 << 1)
8254#define SKIPFUNC (1 << 2)
8255#define SKIPFILE (1 << 3)
8256#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008257static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008258static int skipcount; /* number of levels to skip */
8259static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008260static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008261
Denis Vlasenko4b875702009-03-19 13:30:04 +00008262/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008263static int evalstring(char *s, int mask);
8264
Denis Vlasenko4b875702009-03-19 13:30:04 +00008265/* Called to execute a trap.
8266 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008267 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008268 *
8269 * Perhaps we should avoid entering new trap handlers
8270 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008271 */
8272static int
8273dotrap(void)
8274{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008275 uint8_t *g;
8276 int sig;
8277 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008278
8279 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008280 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008281 xbarrier();
8282
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008283 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008284 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8285 int want_exexit;
8286 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008287
Denis Vlasenko4b875702009-03-19 13:30:04 +00008288 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008289 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008290 t = trap[sig];
8291 /* non-trapped SIGINT is handled separately by raise_interrupt,
8292 * don't upset it by resetting gotsig[SIGINT-1] */
8293 if (sig == SIGINT && !t)
8294 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008295
8296 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008297 *g = 0;
8298 if (!t)
8299 continue;
8300 want_exexit = evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008301 exitstatus = savestatus;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008302 if (want_exexit) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008303 TRACE(("dotrap returns %d\n", want_exexit));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008304 return want_exexit;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008305 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008306 }
8307
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008308 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008309 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008310}
8311
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008312/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008313static void evalloop(union node *, int);
8314static void evalfor(union node *, int);
8315static void evalcase(union node *, int);
8316static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008317static void expredir(union node *);
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008318static void evalpipe(union node *, int);
8319static void evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008320static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008321static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008322
Eric Andersen62483552001-07-10 06:09:16 +00008323/*
Eric Andersenc470f442003-07-28 09:56:35 +00008324 * Evaluate a parse tree. The value is left in the global variable
8325 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008326 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008327static void
Eric Andersenc470f442003-07-28 09:56:35 +00008328evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008329{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008330 struct jmploc *volatile savehandler = exception_handler;
8331 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008332 int checkexit = 0;
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008333 void (*evalfn)(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008334 int status;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008335 int int_level;
8336
8337 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008338
Eric Andersenc470f442003-07-28 09:56:35 +00008339 if (n == NULL) {
8340 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008341 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008342 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008343 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008344
8345 exception_handler = &jmploc;
8346 {
8347 int err = setjmp(jmploc.loc);
8348 if (err) {
8349 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008350 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008351 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8352 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008353 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008354 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008355 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008356 TRACE(("exception %d in evaltree, propagating err=%d\n",
8357 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008358 exception_handler = savehandler;
8359 longjmp(exception_handler->loc, err);
8360 }
8361 }
8362
Eric Andersenc470f442003-07-28 09:56:35 +00008363 switch (n->type) {
8364 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008365#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008366 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008367 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008368 break;
8369#endif
8370 case NNOT:
8371 evaltree(n->nnot.com, EV_TESTED);
8372 status = !exitstatus;
8373 goto setstatus;
8374 case NREDIR:
8375 expredir(n->nredir.redirect);
8376 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8377 if (!status) {
8378 evaltree(n->nredir.n, flags & EV_TESTED);
8379 status = exitstatus;
8380 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008381 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008382 goto setstatus;
8383 case NCMD:
8384 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008385 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008386 if (eflag && !(flags & EV_TESTED))
8387 checkexit = ~0;
8388 goto calleval;
8389 case NFOR:
8390 evalfn = evalfor;
8391 goto calleval;
8392 case NWHILE:
8393 case NUNTIL:
8394 evalfn = evalloop;
8395 goto calleval;
8396 case NSUBSHELL:
8397 case NBACKGND:
8398 evalfn = evalsubshell;
8399 goto calleval;
8400 case NPIPE:
8401 evalfn = evalpipe;
8402 goto checkexit;
8403 case NCASE:
8404 evalfn = evalcase;
8405 goto calleval;
8406 case NAND:
8407 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008408 case NSEMI: {
8409
Eric Andersenc470f442003-07-28 09:56:35 +00008410#if NAND + 1 != NOR
8411#error NAND + 1 != NOR
8412#endif
8413#if NOR + 1 != NSEMI
8414#error NOR + 1 != NSEMI
8415#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008416 unsigned is_or = n->type - NAND;
Eric Andersenc470f442003-07-28 09:56:35 +00008417 evaltree(
8418 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008419 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008420 );
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008421 if (!exitstatus == is_or)
Eric Andersenc470f442003-07-28 09:56:35 +00008422 break;
8423 if (!evalskip) {
8424 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008425 evaln:
Eric Andersenc470f442003-07-28 09:56:35 +00008426 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008427 calleval:
Eric Andersenc470f442003-07-28 09:56:35 +00008428 evalfn(n, flags);
8429 break;
8430 }
8431 break;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008432 }
Eric Andersenc470f442003-07-28 09:56:35 +00008433 case NIF:
8434 evaltree(n->nif.test, EV_TESTED);
8435 if (evalskip)
8436 break;
8437 if (exitstatus == 0) {
8438 n = n->nif.ifpart;
8439 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008440 }
8441 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008442 n = n->nif.elsepart;
8443 goto evaln;
8444 }
8445 goto success;
8446 case NDEFUN:
8447 defun(n->narg.text, n->narg.next);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008448 success:
Eric Andersenc470f442003-07-28 09:56:35 +00008449 status = 0;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008450 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008451 exitstatus = status;
8452 break;
8453 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008454
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008455 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008456 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008457
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008458 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008459 /* Order of checks below is important:
8460 * signal handlers trigger before exit caused by "set -e".
8461 */
8462 if (pending_sig && dotrap())
8463 goto exexit;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008464 if (checkexit & exitstatus)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008465 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008466
8467 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008468 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008469 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008470 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008471
8472 RESTORE_INT(int_level);
8473 TRACE(("leaving evaltree (no interrupts)\n"));
Eric Andersen62483552001-07-10 06:09:16 +00008474}
8475
Eric Andersenc470f442003-07-28 09:56:35 +00008476#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8477static
8478#endif
8479void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8480
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008481static void
Eric Andersenc470f442003-07-28 09:56:35 +00008482evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008483{
8484 int status;
8485
8486 loopnest++;
8487 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008488 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008489 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008490 int i;
8491
Eric Andersencb57d552001-06-28 07:25:16 +00008492 evaltree(n->nbinary.ch1, EV_TESTED);
8493 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008494 skipping:
8495 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008496 evalskip = 0;
8497 continue;
8498 }
8499 if (evalskip == SKIPBREAK && --skipcount <= 0)
8500 evalskip = 0;
8501 break;
8502 }
Eric Andersenc470f442003-07-28 09:56:35 +00008503 i = exitstatus;
8504 if (n->type != NWHILE)
8505 i = !i;
8506 if (i != 0)
8507 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008508 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008509 status = exitstatus;
8510 if (evalskip)
8511 goto skipping;
8512 }
8513 loopnest--;
8514 exitstatus = status;
8515}
8516
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008517static void
Eric Andersenc470f442003-07-28 09:56:35 +00008518evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008519{
8520 struct arglist arglist;
8521 union node *argp;
8522 struct strlist *sp;
8523 struct stackmark smark;
8524
8525 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008526 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008527 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008528 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008529 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008530 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008531 if (evalskip)
8532 goto out;
8533 }
8534 *arglist.lastp = NULL;
8535
8536 exitstatus = 0;
8537 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008538 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008539 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008540 setvar0(n->nfor.var, sp->text);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008541 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008542 if (evalskip) {
8543 if (evalskip == SKIPCONT && --skipcount <= 0) {
8544 evalskip = 0;
8545 continue;
8546 }
8547 if (evalskip == SKIPBREAK && --skipcount <= 0)
8548 evalskip = 0;
8549 break;
8550 }
8551 }
8552 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008553 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008554 popstackmark(&smark);
8555}
8556
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008557static void
Eric Andersenc470f442003-07-28 09:56:35 +00008558evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008559{
8560 union node *cp;
8561 union node *patp;
8562 struct arglist arglist;
8563 struct stackmark smark;
8564
8565 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008566 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008567 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008568 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008569 exitstatus = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008570 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8571 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008572 if (casematch(patp, arglist.list->text)) {
8573 if (evalskip == 0) {
8574 evaltree(cp->nclist.body, flags);
8575 }
8576 goto out;
8577 }
8578 }
8579 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008580 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008581 popstackmark(&smark);
8582}
8583
Eric Andersenc470f442003-07-28 09:56:35 +00008584/*
8585 * Kick off a subshell to evaluate a tree.
8586 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008587static void
Eric Andersenc470f442003-07-28 09:56:35 +00008588evalsubshell(union node *n, int flags)
8589{
8590 struct job *jp;
8591 int backgnd = (n->type == NBACKGND);
8592 int status;
8593
8594 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008595 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008596 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008597 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008598 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008599 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008600 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008601 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008602 flags |= EV_EXIT;
8603 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008604 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008605 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008606 redirect(n->nredir.redirect, 0);
8607 evaltreenr(n->nredir.n, flags);
8608 /* never returns */
8609 }
8610 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008611 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008612 status = waitforjob(jp);
8613 exitstatus = status;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008614 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008615}
8616
Eric Andersenc470f442003-07-28 09:56:35 +00008617/*
8618 * Compute the names of the files in a redirection list.
8619 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008620static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008621static void
8622expredir(union node *n)
8623{
8624 union node *redir;
8625
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008626 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008627 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008628
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008629 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008630 fn.lastp = &fn.list;
8631 switch (redir->type) {
8632 case NFROMTO:
8633 case NFROM:
8634 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008635#if ENABLE_ASH_BASH_COMPAT
8636 case NTO2:
8637#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008638 case NCLOBBER:
8639 case NAPPEND:
8640 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008641 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008642#if ENABLE_ASH_BASH_COMPAT
8643 store_expfname:
8644#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008645#if 0
8646// By the design of stack allocator, the loop of this kind:
8647// while true; do while true; do break; done </dev/null; done
8648// will look like a memory leak: ash plans to free expfname's
8649// of "/dev/null" as soon as it finishes running the loop
8650// (in this case, never).
8651// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008652 if (redir->nfile.expfname)
8653 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008654// It results in corrupted state of stacked allocations.
8655#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008656 redir->nfile.expfname = fn.list->text;
8657 break;
8658 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008659 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008660 if (redir->ndup.vname) {
8661 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008662 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008663 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008664#if ENABLE_ASH_BASH_COMPAT
8665//FIXME: we used expandarg with different args!
8666 if (!isdigit_str9(fn.list->text)) {
8667 /* >&file, not >&fd */
8668 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8669 ash_msg_and_raise_error("redir error");
8670 redir->type = NTO2;
8671 goto store_expfname;
8672 }
8673#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008674 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008675 }
8676 break;
8677 }
8678 }
8679}
8680
Eric Andersencb57d552001-06-28 07:25:16 +00008681/*
Eric Andersencb57d552001-06-28 07:25:16 +00008682 * Evaluate a pipeline. All the processes in the pipeline are children
8683 * of the process creating the pipeline. (This differs from some versions
8684 * of the shell, which make the last process in a pipeline the parent
8685 * of all the rest.)
8686 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008687static void
Eric Andersenc470f442003-07-28 09:56:35 +00008688evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008689{
8690 struct job *jp;
8691 struct nodelist *lp;
8692 int pipelen;
8693 int prevfd;
8694 int pip[2];
8695
Eric Andersenc470f442003-07-28 09:56:35 +00008696 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008697 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008698 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008699 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008700 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008701 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008702 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008703 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008704 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008705 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008706 pip[1] = -1;
8707 if (lp->next) {
8708 if (pipe(pip) < 0) {
8709 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008710 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008711 }
8712 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008713 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008714 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008715 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008716 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008717 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008718 if (prevfd > 0) {
8719 dup2(prevfd, 0);
8720 close(prevfd);
8721 }
8722 if (pip[1] > 1) {
8723 dup2(pip[1], 1);
8724 close(pip[1]);
8725 }
Eric Andersenc470f442003-07-28 09:56:35 +00008726 evaltreenr(lp->n, flags);
8727 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008728 }
8729 if (prevfd >= 0)
8730 close(prevfd);
8731 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008732 /* Don't want to trigger debugging */
8733 if (pip[1] != -1)
8734 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008735 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008736 if (n->npipe.pipe_backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008737 exitstatus = waitforjob(jp);
8738 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00008739 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008740 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008741}
8742
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008743/*
8744 * Controls whether the shell is interactive or not.
8745 */
8746static void
8747setinteractive(int on)
8748{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008749 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008750
8751 if (++on == is_interactive)
8752 return;
8753 is_interactive = on;
8754 setsignal(SIGINT);
8755 setsignal(SIGQUIT);
8756 setsignal(SIGTERM);
8757#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8758 if (is_interactive > 1) {
8759 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008760 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008761
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008762 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008763 /* note: ash and hush share this string */
8764 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008765 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8766 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008767 bb_banner,
8768 "built-in shell (ash)"
8769 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008770 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008771 }
8772 }
8773#endif
8774}
8775
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008776static void
8777optschanged(void)
8778{
8779#if DEBUG
8780 opentrace();
8781#endif
8782 setinteractive(iflag);
8783 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008784#if ENABLE_FEATURE_EDITING_VI
8785 if (viflag)
8786 line_input_state->flags |= VI_MODE;
8787 else
8788 line_input_state->flags &= ~VI_MODE;
8789#else
8790 viflag = 0; /* forcibly keep the option off */
8791#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008792}
8793
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008794static struct localvar *localvars;
8795
8796/*
8797 * Called after a function returns.
8798 * Interrupts must be off.
8799 */
8800static void
8801poplocalvars(void)
8802{
8803 struct localvar *lvp;
8804 struct var *vp;
8805
8806 while ((lvp = localvars) != NULL) {
8807 localvars = lvp->next;
8808 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008809 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008810 if (vp == NULL) { /* $- saved */
8811 memcpy(optlist, lvp->text, sizeof(optlist));
8812 free((char*)lvp->text);
8813 optschanged();
8814 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008815 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008816 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008817 if (vp->var_func)
8818 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008819 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008820 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008821 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008822 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008823 }
8824 free(lvp);
8825 }
8826}
8827
8828static int
8829evalfun(struct funcnode *func, int argc, char **argv, int flags)
8830{
8831 volatile struct shparam saveparam;
8832 struct localvar *volatile savelocalvars;
8833 struct jmploc *volatile savehandler;
8834 struct jmploc jmploc;
8835 int e;
8836
8837 saveparam = shellparam;
8838 savelocalvars = localvars;
8839 e = setjmp(jmploc.loc);
8840 if (e) {
8841 goto funcdone;
8842 }
8843 INT_OFF;
8844 savehandler = exception_handler;
8845 exception_handler = &jmploc;
8846 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008847 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008848 func->count++;
8849 funcnest++;
8850 INT_ON;
8851 shellparam.nparam = argc - 1;
8852 shellparam.p = argv + 1;
8853#if ENABLE_ASH_GETOPTS
8854 shellparam.optind = 1;
8855 shellparam.optoff = -1;
8856#endif
8857 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008858 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008859 INT_OFF;
8860 funcnest--;
8861 freefunc(func);
8862 poplocalvars();
8863 localvars = savelocalvars;
8864 freeparam(&shellparam);
8865 shellparam = saveparam;
8866 exception_handler = savehandler;
8867 INT_ON;
8868 evalskip &= ~SKIPFUNC;
8869 return e;
8870}
8871
Denis Vlasenko131ae172007-02-18 13:00:19 +00008872#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008873static char **
8874parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008875{
8876 char *cp, c;
8877
8878 for (;;) {
8879 cp = *++argv;
8880 if (!cp)
8881 return 0;
8882 if (*cp++ != '-')
8883 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008884 c = *cp++;
8885 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008886 break;
8887 if (c == '-' && !*cp) {
8888 argv++;
8889 break;
8890 }
8891 do {
8892 switch (c) {
8893 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00008894 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00008895 break;
8896 default:
8897 /* run 'typecmd' for other options */
8898 return 0;
8899 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00008900 c = *cp++;
8901 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00008902 }
8903 return argv;
8904}
8905#endif
8906
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008907/*
8908 * Make a variable a local variable. When a variable is made local, it's
8909 * value and flags are saved in a localvar structure. The saved values
8910 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02008911 * "-" as a special case: it makes changes to "set +-options" local
8912 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008913 */
8914static void
8915mklocal(char *name)
8916{
8917 struct localvar *lvp;
8918 struct var **vpp;
8919 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008920 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008921
8922 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008923 /* Cater for duplicate "local". Examples:
8924 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
8925 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
8926 */
8927 lvp = localvars;
8928 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02008929 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008930 if (eq)
8931 setvareq(name, 0);
8932 /* else:
8933 * it's a duplicate "local VAR" declaration, do nothing
8934 */
8935 return;
8936 }
8937 lvp = lvp->next;
8938 }
8939
8940 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008941 if (LONE_DASH(name)) {
8942 char *p;
8943 p = ckmalloc(sizeof(optlist));
8944 lvp->text = memcpy(p, optlist, sizeof(optlist));
8945 vp = NULL;
8946 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008947 vpp = hashvar(name);
8948 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008949 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008950 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008951 if (eq)
8952 setvareq(name, VSTRFIXED);
8953 else
8954 setvar(name, NULL, VSTRFIXED);
8955 vp = *vpp; /* the new variable */
8956 lvp->flags = VUNSET;
8957 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008958 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008959 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008960 /* make sure neither "struct var" nor string gets freed
8961 * during (un)setting:
8962 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008963 vp->flags |= VSTRFIXED|VTEXTFIXED;
8964 if (eq)
8965 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01008966 else
8967 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008968 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008969 }
8970 }
8971 lvp->vp = vp;
8972 lvp->next = localvars;
8973 localvars = lvp;
8974 INT_ON;
8975}
8976
8977/*
8978 * The "local" command.
8979 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008980static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008981localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008982{
8983 char *name;
8984
8985 argv = argptr;
8986 while ((name = *argv++) != NULL) {
8987 mklocal(name);
8988 }
8989 return 0;
8990}
8991
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008992static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008993falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00008994{
8995 return 1;
8996}
8997
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008998static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008999truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009000{
9001 return 0;
9002}
9003
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009004static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009005execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009006{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009007 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009008 iflag = 0; /* exit on error */
9009 mflag = 0;
9010 optschanged();
9011 shellexec(argv + 1, pathval(), 0);
9012 }
9013 return 0;
9014}
9015
9016/*
9017 * The return command.
9018 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009019static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009020returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009021{
9022 /*
9023 * If called outside a function, do what ksh does;
9024 * skip the rest of the file.
9025 */
9026 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9027 return argv[1] ? number(argv[1]) : exitstatus;
9028}
9029
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009030/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009031static int breakcmd(int, char **) FAST_FUNC;
9032static int dotcmd(int, char **) FAST_FUNC;
9033static int evalcmd(int, char **) FAST_FUNC;
9034static int exitcmd(int, char **) FAST_FUNC;
9035static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009036#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009037static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009038#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009039#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009040static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009041#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009042#if MAX_HISTORY
9043static int historycmd(int, char **) FAST_FUNC;
9044#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009045#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009046static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009047#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009048static int readcmd(int, char **) FAST_FUNC;
9049static int setcmd(int, char **) FAST_FUNC;
9050static int shiftcmd(int, char **) FAST_FUNC;
9051static int timescmd(int, char **) FAST_FUNC;
9052static int trapcmd(int, char **) FAST_FUNC;
9053static int umaskcmd(int, char **) FAST_FUNC;
9054static int unsetcmd(int, char **) FAST_FUNC;
9055static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009056
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009057#define BUILTIN_NOSPEC "0"
9058#define BUILTIN_SPECIAL "1"
9059#define BUILTIN_REGULAR "2"
9060#define BUILTIN_SPEC_REG "3"
9061#define BUILTIN_ASSIGN "4"
9062#define BUILTIN_SPEC_ASSG "5"
9063#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009064#define BUILTIN_SPEC_REG_ASSG "7"
9065
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009066/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009067#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009068static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009069#endif
9070#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009071static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009072#endif
9073#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009074static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009075#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009076
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009077/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009078static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009079 { BUILTIN_SPEC_REG "." , dotcmd },
9080 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009081#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009082 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009083#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009084 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009085#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009086#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009087#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009088 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009089#endif
9090#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009091 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009092#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009093 { BUILTIN_SPEC_REG "break" , breakcmd },
9094 { BUILTIN_REGULAR "cd" , cdcmd },
9095 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009096#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009097 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009098#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009099 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009100#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009101 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009102#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009103 { BUILTIN_SPEC_REG "eval" , evalcmd },
9104 { BUILTIN_SPEC_REG "exec" , execcmd },
9105 { BUILTIN_SPEC_REG "exit" , exitcmd },
9106 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9107 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009108#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009109 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009110#endif
9111#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009112 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009113#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009114 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009115#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009116 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009117#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009118#if MAX_HISTORY
9119 { BUILTIN_NOSPEC "history" , historycmd },
9120#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009121#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009122 { BUILTIN_REGULAR "jobs" , jobscmd },
9123 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009124#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009125#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009126 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009127#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009128 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009129#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009130 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009131#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009132 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9133 { BUILTIN_REGULAR "read" , readcmd },
9134 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9135 { BUILTIN_SPEC_REG "return" , returncmd },
9136 { BUILTIN_SPEC_REG "set" , setcmd },
9137 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009138#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009139 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009140#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009141#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009142 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009143#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009144 { BUILTIN_SPEC_REG "times" , timescmd },
9145 { BUILTIN_SPEC_REG "trap" , trapcmd },
9146 { BUILTIN_REGULAR "true" , truecmd },
9147 { BUILTIN_NOSPEC "type" , typecmd },
9148 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9149 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009150#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009151 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009152#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009153 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9154 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009155};
9156
Denis Vlasenko80591b02008-03-25 07:49:43 +00009157/* Should match the above table! */
9158#define COMMANDCMD (builtintab + \
9159 2 + \
9160 1 * ENABLE_ASH_BUILTIN_TEST + \
9161 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9162 1 * ENABLE_ASH_ALIAS + \
9163 1 * ENABLE_ASH_JOB_CONTROL + \
9164 3)
9165#define EXECCMD (builtintab + \
9166 2 + \
9167 1 * ENABLE_ASH_BUILTIN_TEST + \
9168 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9169 1 * ENABLE_ASH_ALIAS + \
9170 1 * ENABLE_ASH_JOB_CONTROL + \
9171 3 + \
9172 1 * ENABLE_ASH_CMDCMD + \
9173 1 + \
9174 ENABLE_ASH_BUILTIN_ECHO + \
9175 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009176
9177/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009178 * Search the table of builtin commands.
9179 */
9180static struct builtincmd *
9181find_builtin(const char *name)
9182{
9183 struct builtincmd *bp;
9184
9185 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009186 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009187 pstrcmp
9188 );
9189 return bp;
9190}
9191
9192/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009193 * Execute a simple command.
9194 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009195static int
9196isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009197{
9198 const char *q = endofname(p);
9199 if (p == q)
9200 return 0;
9201 return *q == '=';
9202}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009203static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009204bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009205{
9206 /* Preserve exitstatus of a previous possible redirection
9207 * as POSIX mandates */
9208 return back_exitstatus;
9209}
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02009210static void
Eric Andersenc470f442003-07-28 09:56:35 +00009211evalcommand(union node *cmd, int flags)
9212{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009213 static const struct builtincmd null_bltin = {
9214 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009215 };
Eric Andersenc470f442003-07-28 09:56:35 +00009216 struct stackmark smark;
9217 union node *argp;
9218 struct arglist arglist;
9219 struct arglist varlist;
9220 char **argv;
9221 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009222 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009223 struct cmdentry cmdentry;
9224 struct job *jp;
9225 char *lastarg;
9226 const char *path;
9227 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009228 int status;
9229 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009230 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009231 smallint cmd_is_exec;
9232 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009233
9234 /* First expand the arguments. */
9235 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9236 setstackmark(&smark);
9237 back_exitstatus = 0;
9238
9239 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009240 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009241 varlist.lastp = &varlist.list;
9242 *varlist.lastp = NULL;
9243 arglist.lastp = &arglist.list;
9244 *arglist.lastp = NULL;
9245
9246 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009247 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009248 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9249 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9250 }
9251
Eric Andersenc470f442003-07-28 09:56:35 +00009252 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9253 struct strlist **spp;
9254
9255 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009256 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009257 expandarg(argp, &arglist, EXP_VARTILDE);
9258 else
9259 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9260
Eric Andersenc470f442003-07-28 09:56:35 +00009261 for (sp = *spp; sp; sp = sp->next)
9262 argc++;
9263 }
9264
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009265 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009266 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009267 TRACE(("evalcommand arg: %s\n", sp->text));
9268 *nargv++ = sp->text;
9269 }
9270 *nargv = NULL;
9271
9272 lastarg = NULL;
9273 if (iflag && funcnest == 0 && argc > 0)
9274 lastarg = nargv[-1];
9275
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009276 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009277 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009278 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009279
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009280 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009281 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9282 struct strlist **spp;
9283 char *p;
9284
9285 spp = varlist.lastp;
9286 expandarg(argp, &varlist, EXP_VARTILDE);
9287
9288 /*
9289 * Modify the command lookup path, if a PATH= assignment
9290 * is present
9291 */
9292 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009293 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009294 path = p;
9295 }
9296
9297 /* Print the command if xflag is set. */
9298 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009299 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009300 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009301
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009302 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009303 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009304 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009305 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009306 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009307 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009308 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009309 }
9310 sp = arglist.list;
9311 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009312 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009313 }
9314
9315 cmd_is_exec = 0;
9316 spclbltin = -1;
9317
9318 /* Now locate the command. */
9319 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009320 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009321#if ENABLE_ASH_CMDCMD
9322 const char *oldpath = path + 5;
9323#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009324 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009325 for (;;) {
9326 find_command(argv[0], &cmdentry, cmd_flag, path);
9327 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009328 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009329 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009330 goto bail;
9331 }
9332
9333 /* implement bltin and command here */
9334 if (cmdentry.cmdtype != CMDBUILTIN)
9335 break;
9336 if (spclbltin < 0)
9337 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9338 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009339 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009340#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009341 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009342 path = oldpath;
9343 nargv = parse_command_args(argv, &path);
9344 if (!nargv)
9345 break;
9346 argc -= nargv - argv;
9347 argv = nargv;
9348 cmd_flag |= DO_NOFUNC;
9349 } else
9350#endif
9351 break;
9352 }
9353 }
9354
9355 if (status) {
9356 /* We have a redirection error. */
9357 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009358 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009359 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009360 exitstatus = status;
9361 goto out;
9362 }
9363
9364 /* Execute the command. */
9365 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009366 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009367
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009368#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009369/* (1) BUG: if variables are set, we need to fork, or save/restore them
9370 * around run_nofork_applet() call.
9371 * (2) Should this check also be done in forkshell()?
9372 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9373 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009374 /* find_command() encodes applet_no as (-2 - applet_no) */
9375 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009376 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009377 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009378 /* run <applet>_main() */
9379 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009380 break;
9381 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009382#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009383 /* Can we avoid forking off? For example, very last command
9384 * in a script or a subshell does not need forking,
9385 * we can just exec it.
9386 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009387 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009388 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009389 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009390 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009391 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009392 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009393 exitstatus = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009394 INT_ON;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009395 TRACE(("forked child exited with %d\n", exitstatus));
Eric Andersenc470f442003-07-28 09:56:35 +00009396 break;
9397 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009398 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009399 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009400 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009401 }
9402 listsetvar(varlist.list, VEXPORT|VSTACK);
9403 shellexec(argv, path, cmdentry.u.index);
9404 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009405 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009406 case CMDBUILTIN:
9407 cmdenviron = varlist.list;
9408 if (cmdenviron) {
9409 struct strlist *list = cmdenviron;
9410 int i = VNOSET;
9411 if (spclbltin > 0 || argc == 0) {
9412 i = 0;
9413 if (cmd_is_exec && argc > 1)
9414 i = VEXPORT;
9415 }
9416 listsetvar(list, i);
9417 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009418 /* Tight loop with builtins only:
9419 * "while kill -0 $child; do true; done"
9420 * will never exit even if $child died, unless we do this
9421 * to reap the zombie and make kill detect that it's gone: */
9422 dowait(DOWAIT_NONBLOCK, NULL);
9423
Eric Andersenc470f442003-07-28 09:56:35 +00009424 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9425 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009426 int i = exception_type;
Eric Andersenc470f442003-07-28 09:56:35 +00009427 if (i == EXEXIT)
9428 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009429 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009430 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009431 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009432 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009433 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009434 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009435 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009436 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009437 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009438 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009439 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009440 }
9441 break;
9442
9443 case CMDFUNCTION:
9444 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009445 /* See above for the rationale */
9446 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009447 if (evalfun(cmdentry.u.func, argc, argv, flags))
9448 goto raise;
9449 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009450
9451 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009452
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009453 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009454 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009455 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009456 /* dsl: I think this is intended to be used to support
9457 * '_' in 'vi' command mode during line editing...
9458 * However I implemented that within libedit itself.
9459 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009460 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009461 }
Eric Andersenc470f442003-07-28 09:56:35 +00009462 popstackmark(&smark);
9463}
9464
9465static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009466evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9467{
Eric Andersenc470f442003-07-28 09:56:35 +00009468 char *volatile savecmdname;
9469 struct jmploc *volatile savehandler;
9470 struct jmploc jmploc;
9471 int i;
9472
9473 savecmdname = commandname;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009474 i = setjmp(jmploc.loc);
9475 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009476 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009477 savehandler = exception_handler;
9478 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009479 commandname = argv[0];
9480 argptr = argv + 1;
9481 optptr = NULL; /* initialize nextopt */
9482 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009483 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009484 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009485 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009486 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009487 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009488 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009489
9490 return i;
9491}
9492
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009493static int
9494goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009495{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009496 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009497}
9498
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009499
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009500/*
9501 * Search for a command. This is called before we fork so that the
9502 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009503 * the child. The check for "goodname" is an overly conservative
9504 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009505 */
Eric Andersenc470f442003-07-28 09:56:35 +00009506static void
9507prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009508{
9509 struct cmdentry entry;
9510
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009511 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9512 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009513}
9514
Eric Andersencb57d552001-06-28 07:25:16 +00009515
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009516/* ============ Builtin commands
9517 *
9518 * Builtin commands whose functions are closely tied to evaluation
9519 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009520 */
9521
9522/*
Eric Andersencb57d552001-06-28 07:25:16 +00009523 * Handle break and continue commands. Break, continue, and return are
9524 * all handled by setting the evalskip flag. The evaluation routines
9525 * above all check this flag, and if it is set they start skipping
9526 * commands rather than executing them. The variable skipcount is
9527 * the number of loops to break/continue, or the number of function
9528 * levels to return. (The latter is always 1.) It should probably
9529 * be an error to break out of more loops than exist, but it isn't
9530 * in the standard shell so we don't make it one here.
9531 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009532static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009533breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009534{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009535 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009536
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009537 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009538 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009539 if (n > loopnest)
9540 n = loopnest;
9541 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009542 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009543 skipcount = n;
9544 }
9545 return 0;
9546}
9547
Eric Andersenc470f442003-07-28 09:56:35 +00009548
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009549/* ============ input.c
9550 *
Eric Andersen90898442003-08-06 11:20:52 +00009551 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009552 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009553
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009554enum {
9555 INPUT_PUSH_FILE = 1,
9556 INPUT_NOFILE_OK = 2,
9557};
Eric Andersencb57d552001-06-28 07:25:16 +00009558
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009559static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009560/* values of checkkwd variable */
9561#define CHKALIAS 0x1
9562#define CHKKWD 0x2
9563#define CHKNL 0x4
9564
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009565/*
9566 * Push a string back onto the input at this current parsefile level.
9567 * We handle aliases this way.
9568 */
9569#if !ENABLE_ASH_ALIAS
9570#define pushstring(s, ap) pushstring(s)
9571#endif
9572static void
9573pushstring(char *s, struct alias *ap)
9574{
9575 struct strpush *sp;
9576 int len;
9577
9578 len = strlen(s);
9579 INT_OFF;
9580 if (g_parsefile->strpush) {
9581 sp = ckzalloc(sizeof(*sp));
9582 sp->prev = g_parsefile->strpush;
9583 } else {
9584 sp = &(g_parsefile->basestrpush);
9585 }
9586 g_parsefile->strpush = sp;
9587 sp->prev_string = g_parsefile->next_to_pgetc;
9588 sp->prev_left_in_line = g_parsefile->left_in_line;
9589#if ENABLE_ASH_ALIAS
9590 sp->ap = ap;
9591 if (ap) {
9592 ap->flag |= ALIASINUSE;
9593 sp->string = s;
9594 }
9595#endif
9596 g_parsefile->next_to_pgetc = s;
9597 g_parsefile->left_in_line = len;
9598 INT_ON;
9599}
9600
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009601static void
9602popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009603{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009604 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009605
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009606 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009607#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009608 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009609 if (g_parsefile->next_to_pgetc[-1] == ' '
9610 || g_parsefile->next_to_pgetc[-1] == '\t'
9611 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009612 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009613 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009614 if (sp->string != sp->ap->val) {
9615 free(sp->string);
9616 }
9617 sp->ap->flag &= ~ALIASINUSE;
9618 if (sp->ap->flag & ALIASDEAD) {
9619 unalias(sp->ap->name);
9620 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009621 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009622#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009623 g_parsefile->next_to_pgetc = sp->prev_string;
9624 g_parsefile->left_in_line = sp->prev_left_in_line;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009625 g_parsefile->strpush = sp->prev;
9626 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009627 free(sp);
9628 INT_ON;
9629}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009630
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009631//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9632//it peeks whether it is &>, and then pushes back both chars.
9633//This function needs to save last *next_to_pgetc to buf[0]
9634//to make two pungetc() reliable. Currently,
9635// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009636static int
9637preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009638{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009639 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009640 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009641
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009642 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009643#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009644 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009645 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009646 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009647 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009648 int timeout = -1;
9649# if ENABLE_ASH_IDLE_TIMEOUT
9650 if (iflag) {
9651 const char *tmout_var = lookupvar("TMOUT");
9652 if (tmout_var) {
9653 timeout = atoi(tmout_var) * 1000;
9654 if (timeout <= 0)
9655 timeout = -1;
9656 }
9657 }
9658# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009659# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009660 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009661# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009662 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009663 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009664 if (nr == 0) {
9665 /* Ctrl+C pressed */
9666 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009667 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009668 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009669 raise(SIGINT);
9670 return 1;
9671 }
Eric Andersenc470f442003-07-28 09:56:35 +00009672 goto retry;
9673 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009674 if (nr < 0) {
9675 if (errno == 0) {
9676 /* Ctrl+D pressed */
9677 nr = 0;
9678 }
9679# if ENABLE_ASH_IDLE_TIMEOUT
9680 else if (errno == EAGAIN && timeout > 0) {
9681 printf("\007timed out waiting for input: auto-logout\n");
9682 exitshell();
9683 }
9684# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009685 }
Eric Andersencb57d552001-06-28 07:25:16 +00009686 }
9687#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009688 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009689#endif
9690
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009691#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009692 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009693 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009694 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009695 if (flags >= 0 && (flags & O_NONBLOCK)) {
9696 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009697 if (fcntl(0, F_SETFL, flags) >= 0) {
9698 out2str("sh: turning off NDELAY mode\n");
9699 goto retry;
9700 }
9701 }
9702 }
9703 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009704#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009705 return nr;
9706}
9707
9708/*
9709 * Refill the input buffer and return the next input character:
9710 *
9711 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009712 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9713 * or we are reading from a string so we can't refill the buffer,
9714 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009715 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009716 * 4) Process input up to the next newline, deleting nul characters.
9717 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009718//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9719#define pgetc_debug(...) ((void)0)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009720static int
Eric Andersenc470f442003-07-28 09:56:35 +00009721preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009722{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009723 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009724 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009725
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009726 while (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009727#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009728 if (g_parsefile->left_in_line == -1
9729 && g_parsefile->strpush->ap
9730 && g_parsefile->next_to_pgetc[-1] != ' '
9731 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009732 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009733 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009734 return PEOA;
9735 }
Eric Andersen2870d962001-07-02 17:27:21 +00009736#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009737 popstring();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009738 /* try "pgetc" now: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009739 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9740 g_parsefile->left_in_line,
9741 g_parsefile->next_to_pgetc,
9742 g_parsefile->next_to_pgetc);
9743 if (--g_parsefile->left_in_line >= 0)
9744 return (unsigned char)(*g_parsefile->next_to_pgetc++);
Eric Andersencb57d552001-06-28 07:25:16 +00009745 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009746 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009747 * "pgetc" needs refilling.
9748 */
9749
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009750 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009751 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009752 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009753 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009754 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009755 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009756 /* even in failure keep left_in_line and next_to_pgetc
9757 * in lock step, for correct multi-layer pungetc.
9758 * left_in_line was decremented before preadbuffer(),
9759 * must inc next_to_pgetc: */
9760 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009761 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009762 }
Eric Andersencb57d552001-06-28 07:25:16 +00009763
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009764 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009765 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009766 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009767 again:
9768 more = preadfd();
9769 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009770 /* don't try reading again */
9771 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009772 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009773 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009774 return PEOF;
9775 }
9776 }
9777
Denis Vlasenko727752d2008-11-28 03:41:47 +00009778 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009779 * Set g_parsefile->left_in_line
9780 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009781 * NUL chars are deleted.
9782 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009783 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009784 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009785 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009786
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009787 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009788
Denis Vlasenko727752d2008-11-28 03:41:47 +00009789 c = *q;
9790 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009791 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009792 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009793 q++;
9794 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009795 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009796 break;
9797 }
Eric Andersencb57d552001-06-28 07:25:16 +00009798 }
9799
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009800 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009801 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9802 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009803 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009804 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009805 }
9806 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009807 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009808
Eric Andersencb57d552001-06-28 07:25:16 +00009809 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009810 char save = *q;
9811 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009812 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009813 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009814 }
9815
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009816 pgetc_debug("preadbuffer at %d:%p'%s'",
9817 g_parsefile->left_in_line,
9818 g_parsefile->next_to_pgetc,
9819 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009820 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009821}
9822
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009823#define pgetc_as_macro() \
9824 (--g_parsefile->left_in_line >= 0 \
Denys Vlasenkocd716832009-11-28 22:14:02 +01009825 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009826 : preadbuffer() \
9827 )
Denis Vlasenko727752d2008-11-28 03:41:47 +00009828
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009829static int
9830pgetc(void)
9831{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009832 pgetc_debug("pgetc_fast at %d:%p'%s'",
9833 g_parsefile->left_in_line,
9834 g_parsefile->next_to_pgetc,
9835 g_parsefile->next_to_pgetc);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009836 return pgetc_as_macro();
9837}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009838
9839#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009840# define pgetc_fast() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009841#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009842# define pgetc_fast() pgetc_as_macro()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009843#endif
9844
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009845#if ENABLE_ASH_ALIAS
9846static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009847pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009848{
9849 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009850 do {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009851 pgetc_debug("pgetc_fast at %d:%p'%s'",
9852 g_parsefile->left_in_line,
9853 g_parsefile->next_to_pgetc,
9854 g_parsefile->next_to_pgetc);
Denis Vlasenko834dee72008-10-07 09:18:30 +00009855 c = pgetc_fast();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009856 } while (c == PEOA);
9857 return c;
9858}
9859#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009860# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009861#endif
9862
9863/*
9864 * Read a line from the script.
9865 */
9866static char *
9867pfgets(char *line, int len)
9868{
9869 char *p = line;
9870 int nleft = len;
9871 int c;
9872
9873 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009874 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009875 if (c == PEOF) {
9876 if (p == line)
9877 return NULL;
9878 break;
9879 }
9880 *p++ = c;
9881 if (c == '\n')
9882 break;
9883 }
9884 *p = '\0';
9885 return line;
9886}
9887
Eric Andersenc470f442003-07-28 09:56:35 +00009888/*
9889 * Undo the last call to pgetc. Only one character may be pushed back.
9890 * PEOF may be pushed back.
9891 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009892static void
Eric Andersenc470f442003-07-28 09:56:35 +00009893pungetc(void)
9894{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009895 g_parsefile->left_in_line++;
9896 g_parsefile->next_to_pgetc--;
9897 pgetc_debug("pushed back to %d:%p'%s'",
9898 g_parsefile->left_in_line,
9899 g_parsefile->next_to_pgetc,
9900 g_parsefile->next_to_pgetc);
Eric Andersencb57d552001-06-28 07:25:16 +00009901}
9902
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009903/*
9904 * To handle the "." command, a stack of input files is used. Pushfile
9905 * adds a new entry to the stack and popfile restores the previous level.
9906 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009907static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009908pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009909{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009910 struct parsefile *pf;
9911
Denis Vlasenko597906c2008-02-20 16:38:54 +00009912 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009913 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009914 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +00009915 /*pf->strpush = NULL; - ckzalloc did it */
9916 /*pf->basestrpush.prev = NULL;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009917 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009918}
9919
9920static void
9921popfile(void)
9922{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009923 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +00009924
Denis Vlasenkob012b102007-02-19 22:43:01 +00009925 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009926 if (pf->pf_fd >= 0)
9927 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +00009928 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009929 while (pf->strpush)
9930 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009931 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009932 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009933 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009934}
9935
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009936/*
9937 * Return to top level.
9938 */
9939static void
9940popallfiles(void)
9941{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009942 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009943 popfile();
9944}
9945
9946/*
9947 * Close the file(s) that the shell is reading commands from. Called
9948 * after a fork is done.
9949 */
9950static void
9951closescript(void)
9952{
9953 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009954 if (g_parsefile->pf_fd > 0) {
9955 close(g_parsefile->pf_fd);
9956 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009957 }
9958}
9959
9960/*
9961 * Like setinputfile, but takes an open file descriptor. Call this with
9962 * interrupts off.
9963 */
9964static void
9965setinputfd(int fd, int push)
9966{
Denis Vlasenko96e1b382007-09-30 23:50:48 +00009967 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009968 if (push) {
9969 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009970 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009971 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009972 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009973 if (g_parsefile->buf == NULL)
9974 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009975 g_parsefile->left_in_buffer = 0;
9976 g_parsefile->left_in_line = 0;
9977 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009978}
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009979
Eric Andersenc470f442003-07-28 09:56:35 +00009980/*
9981 * Set the input to take input from a file. If push is set, push the
9982 * old input onto the stack first.
9983 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009984static int
9985setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00009986{
9987 int fd;
9988 int fd2;
9989
Denis Vlasenkob012b102007-02-19 22:43:01 +00009990 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009991 fd = open(fname, O_RDONLY);
9992 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009993 if (flags & INPUT_NOFILE_OK)
9994 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00009995 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009996 }
Eric Andersenc470f442003-07-28 09:56:35 +00009997 if (fd < 10) {
9998 fd2 = copyfd(fd, 10);
9999 close(fd);
10000 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010001 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010002 fd = fd2;
10003 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010004 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010005 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010006 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010007 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010008}
10009
Eric Andersencb57d552001-06-28 07:25:16 +000010010/*
10011 * Like setinputfile, but takes input from a string.
10012 */
Eric Andersenc470f442003-07-28 09:56:35 +000010013static void
10014setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010015{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010016 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010017 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010018 g_parsefile->next_to_pgetc = string;
10019 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010020 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010021 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010022 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010023}
10024
10025
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010026/* ============ mail.c
10027 *
10028 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010029 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010030
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010031#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010032
Eric Andersencb57d552001-06-28 07:25:16 +000010033#define MAXMBOXES 10
10034
Eric Andersenc470f442003-07-28 09:56:35 +000010035/* times of mailboxes */
10036static time_t mailtime[MAXMBOXES];
10037/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010038static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010039
Eric Andersencb57d552001-06-28 07:25:16 +000010040/*
Eric Andersenc470f442003-07-28 09:56:35 +000010041 * Print appropriate message(s) if mail has arrived.
10042 * If mail_var_path_changed is set,
10043 * then the value of MAIL has mail_var_path_changed,
10044 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010045 */
Eric Andersenc470f442003-07-28 09:56:35 +000010046static void
10047chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010048{
Eric Andersencb57d552001-06-28 07:25:16 +000010049 const char *mpath;
10050 char *p;
10051 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +000010052 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +000010053 struct stackmark smark;
10054 struct stat statb;
10055
Eric Andersencb57d552001-06-28 07:25:16 +000010056 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010057 mpath = mpathset() ? mpathval() : mailval();
10058 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010059 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010060 if (p == NULL)
10061 break;
10062 if (*p == '\0')
10063 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010064 for (q = p; *q; q++)
10065 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010066#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010067 if (q[-1] != '/')
10068 abort();
10069#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010070 q[-1] = '\0'; /* delete trailing '/' */
10071 if (stat(p, &statb) < 0) {
10072 *mtp = 0;
10073 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010074 }
Eric Andersenc470f442003-07-28 09:56:35 +000010075 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
10076 fprintf(
Denys Vlasenkoea8b2522010-06-02 12:57:26 +020010077 stderr, "%s\n",
Eric Andersenc470f442003-07-28 09:56:35 +000010078 pathopt ? pathopt : "you have mail"
10079 );
10080 }
10081 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +000010082 }
Eric Andersenc470f442003-07-28 09:56:35 +000010083 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010084 popstackmark(&smark);
10085}
Eric Andersencb57d552001-06-28 07:25:16 +000010086
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010087static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010088changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010089{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010090 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010091}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010092
Denis Vlasenko131ae172007-02-18 13:00:19 +000010093#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010094
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010095
10096/* ============ ??? */
10097
Eric Andersencb57d552001-06-28 07:25:16 +000010098/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010099 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010100 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010101static void
10102setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010103{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010104 char **newparam;
10105 char **ap;
10106 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010107
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010108 for (nparam = 0; argv[nparam]; nparam++)
10109 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010110 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10111 while (*argv) {
10112 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010113 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010114 *ap = NULL;
10115 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010116 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010117 shellparam.nparam = nparam;
10118 shellparam.p = newparam;
10119#if ENABLE_ASH_GETOPTS
10120 shellparam.optind = 1;
10121 shellparam.optoff = -1;
10122#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010123}
10124
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010125/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010126 * Process shell options. The global variable argptr contains a pointer
10127 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010128 *
10129 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10130 * For a non-interactive shell, an error condition encountered
10131 * by a special built-in ... shall cause the shell to write a diagnostic message
10132 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010133 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010134 * ...
10135 * Utility syntax error (option or operand error) Shall exit
10136 * ...
10137 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10138 * we see that bash does not do that (set "finishes" with error code 1 instead,
10139 * and shell continues), and people rely on this behavior!
10140 * Testcase:
10141 * set -o barfoo 2>/dev/null
10142 * echo $?
10143 *
10144 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010145 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010146static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010147plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010148{
10149 int i;
10150
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010151 if (name) {
10152 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010153 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010154 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010155 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010156 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010157 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010158 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010159 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010160 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010161 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010162 if (val) {
10163 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10164 } else {
10165 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10166 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010167 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010168 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010169}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010170static void
10171setoption(int flag, int val)
10172{
10173 int i;
10174
10175 for (i = 0; i < NOPTS; i++) {
10176 if (optletters(i) == flag) {
10177 optlist[i] = val;
10178 return;
10179 }
10180 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010181 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010182 /* NOTREACHED */
10183}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010184static int
Eric Andersenc470f442003-07-28 09:56:35 +000010185options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010186{
10187 char *p;
10188 int val;
10189 int c;
10190
10191 if (cmdline)
10192 minusc = NULL;
10193 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010194 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010195 if (c != '-' && c != '+')
10196 break;
10197 argptr++;
10198 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010199 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010200 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010201 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010202 if (!cmdline) {
10203 /* "-" means turn off -x and -v */
10204 if (p[0] == '\0')
10205 xflag = vflag = 0;
10206 /* "--" means reset params */
10207 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010208 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010209 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010210 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010211 }
Eric Andersencb57d552001-06-28 07:25:16 +000010212 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010213 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010214 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010215 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010216 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010217 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010218 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010219 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010220 /* it already printed err message */
10221 return 1; /* error */
10222 }
Eric Andersencb57d552001-06-28 07:25:16 +000010223 if (*argptr)
10224 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010225 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10226 isloginsh = 1;
10227 /* bash does not accept +-login, we also won't */
10228 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010229 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010230 isloginsh = 1;
10231 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010232 } else {
10233 setoption(c, val);
10234 }
10235 }
10236 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010237 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010238}
10239
Eric Andersencb57d552001-06-28 07:25:16 +000010240/*
Eric Andersencb57d552001-06-28 07:25:16 +000010241 * The shift builtin command.
10242 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010243static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010244shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010245{
10246 int n;
10247 char **ap1, **ap2;
10248
10249 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010250 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010251 n = number(argv[1]);
10252 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010253 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010254 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010255 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010256 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010257 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010258 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010259 }
10260 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010261 while ((*ap2++ = *ap1++) != NULL)
10262 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010263#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010264 shellparam.optind = 1;
10265 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010266#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010267 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010268 return 0;
10269}
10270
Eric Andersencb57d552001-06-28 07:25:16 +000010271/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010272 * POSIX requires that 'set' (but not export or readonly) output the
10273 * variables in lexicographic order - by the locale's collating order (sigh).
10274 * Maybe we could keep them in an ordered balanced binary tree
10275 * instead of hashed lists.
10276 * For now just roll 'em through qsort for printing...
10277 */
10278static int
10279showvars(const char *sep_prefix, int on, int off)
10280{
10281 const char *sep;
10282 char **ep, **epend;
10283
10284 ep = listvars(on, off, &epend);
10285 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10286
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010287 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010288
10289 for (; ep < epend; ep++) {
10290 const char *p;
10291 const char *q;
10292
10293 p = strchrnul(*ep, '=');
10294 q = nullstr;
10295 if (*p)
10296 q = single_quote(++p);
10297 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10298 }
10299 return 0;
10300}
10301
10302/*
Eric Andersencb57d552001-06-28 07:25:16 +000010303 * The set command builtin.
10304 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010305static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010306setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010307{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010308 int retval;
10309
Denis Vlasenko68404f12008-03-17 09:00:54 +000010310 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010311 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010312
Denis Vlasenkob012b102007-02-19 22:43:01 +000010313 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010314 retval = options(/*cmdline:*/ 0);
10315 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010316 optschanged();
10317 if (*argptr != NULL) {
10318 setparam(argptr);
10319 }
Eric Andersencb57d552001-06-28 07:25:16 +000010320 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010321 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010322 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010323}
10324
Denis Vlasenko131ae172007-02-18 13:00:19 +000010325#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010326static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010327change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010328{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010329 uint32_t t;
10330
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010331 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010332 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010333 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010334 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010335 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010336 vrandom.flags &= ~VNOFUNC;
10337 } else {
10338 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010339 t = strtoul(value, NULL, 10);
10340 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010341 }
Eric Andersenef02f822004-03-11 13:34:24 +000010342}
Eric Andersen16767e22004-03-16 05:14:10 +000010343#endif
10344
Denis Vlasenko131ae172007-02-18 13:00:19 +000010345#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010346static int
Eric Andersenc470f442003-07-28 09:56:35 +000010347getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010348{
10349 char *p, *q;
10350 char c = '?';
10351 int done = 0;
10352 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +000010353 char s[12];
10354 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010355
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010356 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010357 return 1;
10358 optnext = optfirst + *param_optind - 1;
10359
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010360 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010361 p = NULL;
10362 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010363 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010364 if (p == NULL || *p == '\0') {
10365 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010366 p = *optnext;
10367 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010368 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010369 p = NULL;
10370 done = 1;
10371 goto out;
10372 }
10373 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010374 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010375 goto atend;
10376 }
10377
10378 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010379 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010380 if (*q == '\0') {
10381 if (optstr[0] == ':') {
10382 s[0] = c;
10383 s[1] = '\0';
10384 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010385 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010386 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010387 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010388 }
10389 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010390 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010391 }
10392 if (*++q == ':')
10393 q++;
10394 }
10395
10396 if (*++q == ':') {
10397 if (*p == '\0' && (p = *optnext) == NULL) {
10398 if (optstr[0] == ':') {
10399 s[0] = c;
10400 s[1] = '\0';
10401 err |= setvarsafe("OPTARG", s, 0);
10402 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010403 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010404 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010405 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010406 c = '?';
10407 }
Eric Andersenc470f442003-07-28 09:56:35 +000010408 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010409 }
10410
10411 if (p == *optnext)
10412 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010413 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010414 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010415 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010416 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010417 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010418 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010419 *param_optind = optnext - optfirst + 1;
10420 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +000010421 err |= setvarsafe("OPTIND", s, VNOFUNC);
10422 s[0] = c;
10423 s[1] = '\0';
10424 err |= setvarsafe(optvar, s, 0);
10425 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010426 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010427 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010428 flush_stdout_stderr();
10429 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010430 }
10431 return done;
10432}
Eric Andersenc470f442003-07-28 09:56:35 +000010433
10434/*
10435 * The getopts builtin. Shellparam.optnext points to the next argument
10436 * to be processed. Shellparam.optptr points to the next character to
10437 * be processed in the current argument. If shellparam.optnext is NULL,
10438 * then it's the first time getopts has been called.
10439 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010440static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010441getoptscmd(int argc, char **argv)
10442{
10443 char **optbase;
10444
10445 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010446 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010447 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010448 optbase = shellparam.p;
10449 if (shellparam.optind > shellparam.nparam + 1) {
10450 shellparam.optind = 1;
10451 shellparam.optoff = -1;
10452 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010453 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010454 optbase = &argv[3];
10455 if (shellparam.optind > argc - 2) {
10456 shellparam.optind = 1;
10457 shellparam.optoff = -1;
10458 }
10459 }
10460
10461 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010462 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010463}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010464#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010465
Eric Andersencb57d552001-06-28 07:25:16 +000010466
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010467/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010468
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010469struct heredoc {
10470 struct heredoc *next; /* next here document in list */
10471 union node *here; /* redirection node */
10472 char *eofmark; /* string indicating end of input */
10473 smallint striptabs; /* if set, strip leading tabs */
10474};
10475
10476static smallint tokpushback; /* last token pushed back */
10477static smallint parsebackquote; /* nonzero if we are inside backquotes */
10478static smallint quoteflag; /* set if (part of) last token was quoted */
10479static token_id_t lasttoken; /* last token read (integer id Txxx) */
10480static struct heredoc *heredoclist; /* list of here documents to read */
10481static char *wordtext; /* text of last word returned by readtoken */
10482static struct nodelist *backquotelist;
10483static union node *redirnode;
10484static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010485
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010486static const char *
10487tokname(char *buf, int tok)
10488{
10489 if (tok < TSEMI)
10490 return tokname_array[tok] + 1;
10491 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10492 return buf;
10493}
10494
10495/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010496 * Called when an unexpected token is read during the parse. The argument
10497 * is the token that is expected, or -1 if more than one type of token can
10498 * occur at this point.
10499 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010500static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010501static void
10502raise_error_unexpected_syntax(int token)
10503{
10504 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010505 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010506 int l;
10507
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010508 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010509 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010510 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010511 raise_error_syntax(msg);
10512 /* NOTREACHED */
10513}
Eric Andersencb57d552001-06-28 07:25:16 +000010514
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010515#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010516
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010517/* parsing is heavily cross-recursive, need these forward decls */
10518static union node *andor(void);
10519static union node *pipeline(void);
10520static union node *parse_command(void);
10521static void parseheredoc(void);
Denys Vlasenko7e661022015-02-05 21:00:17 +010010522static char nexttoken_ends_list(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010523static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010524
Eric Andersenc470f442003-07-28 09:56:35 +000010525static union node *
10526list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010527{
10528 union node *n1, *n2, *n3;
10529 int tok;
10530
Eric Andersenc470f442003-07-28 09:56:35 +000010531 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko7e661022015-02-05 21:00:17 +010010532 if (nlflag == 2 && nexttoken_ends_list())
Eric Andersencb57d552001-06-28 07:25:16 +000010533 return NULL;
10534 n1 = NULL;
10535 for (;;) {
10536 n2 = andor();
10537 tok = readtoken();
10538 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010539 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010540 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010541 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010542 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010543 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010544 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010545 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010546 n2 = n3;
10547 }
10548 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010549 }
10550 }
10551 if (n1 == NULL) {
10552 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010553 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010554 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010555 n3->type = NSEMI;
10556 n3->nbinary.ch1 = n1;
10557 n3->nbinary.ch2 = n2;
10558 n1 = n3;
10559 }
10560 switch (tok) {
10561 case TBACKGND:
10562 case TSEMI:
10563 tok = readtoken();
10564 /* fall through */
10565 case TNL:
10566 if (tok == TNL) {
10567 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +000010568 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +000010569 return n1;
10570 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010571 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010572 }
Eric Andersenc470f442003-07-28 09:56:35 +000010573 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko7e661022015-02-05 21:00:17 +010010574 if (nexttoken_ends_list()) {
10575 /* Testcase: "<<EOF; then <W".
10576 * It used to segfault w/o this check:
10577 */
10578 if (heredoclist) {
10579 raise_error_unexpected_syntax(-1);
10580 }
Eric Andersencb57d552001-06-28 07:25:16 +000010581 return n1;
Denys Vlasenko7e661022015-02-05 21:00:17 +010010582 }
Eric Andersencb57d552001-06-28 07:25:16 +000010583 break;
10584 case TEOF:
10585 if (heredoclist)
10586 parseheredoc();
10587 else
Eric Andersenc470f442003-07-28 09:56:35 +000010588 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +000010589 return n1;
10590 default:
Eric Andersenc470f442003-07-28 09:56:35 +000010591 if (nlflag == 1)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010592 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010593 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010594 return n1;
10595 }
10596 }
10597}
10598
Eric Andersenc470f442003-07-28 09:56:35 +000010599static union node *
10600andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010601{
Eric Andersencb57d552001-06-28 07:25:16 +000010602 union node *n1, *n2, *n3;
10603 int t;
10604
Eric Andersencb57d552001-06-28 07:25:16 +000010605 n1 = pipeline();
10606 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010607 t = readtoken();
10608 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010609 t = NAND;
10610 } else if (t == TOR) {
10611 t = NOR;
10612 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010613 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010614 return n1;
10615 }
Eric Andersenc470f442003-07-28 09:56:35 +000010616 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010617 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010618 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010619 n3->type = t;
10620 n3->nbinary.ch1 = n1;
10621 n3->nbinary.ch2 = n2;
10622 n1 = n3;
10623 }
10624}
10625
Eric Andersenc470f442003-07-28 09:56:35 +000010626static union node *
10627pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010628{
Eric Andersencb57d552001-06-28 07:25:16 +000010629 union node *n1, *n2, *pipenode;
10630 struct nodelist *lp, *prev;
10631 int negate;
10632
10633 negate = 0;
10634 TRACE(("pipeline: entered\n"));
10635 if (readtoken() == TNOT) {
10636 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010637 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010638 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010639 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010640 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010641 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010642 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010643 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010644 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010645 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010646 pipenode->npipe.cmdlist = lp;
10647 lp->n = n1;
10648 do {
10649 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010650 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010651 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010652 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010653 prev->next = lp;
10654 } while (readtoken() == TPIPE);
10655 lp->next = NULL;
10656 n1 = pipenode;
10657 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010658 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010659 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010660 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010661 n2->type = NNOT;
10662 n2->nnot.com = n1;
10663 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010664 }
10665 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010666}
10667
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010668static union node *
10669makename(void)
10670{
10671 union node *n;
10672
Denis Vlasenko597906c2008-02-20 16:38:54 +000010673 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010674 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010675 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010676 n->narg.text = wordtext;
10677 n->narg.backquote = backquotelist;
10678 return n;
10679}
10680
10681static void
10682fixredir(union node *n, const char *text, int err)
10683{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010684 int fd;
10685
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010686 TRACE(("Fix redir %s %d\n", text, err));
10687 if (!err)
10688 n->ndup.vname = NULL;
10689
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010690 fd = bb_strtou(text, NULL, 10);
10691 if (!errno && fd >= 0)
10692 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010693 else if (LONE_DASH(text))
10694 n->ndup.dupfd = -1;
10695 else {
10696 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010697 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010698 n->ndup.vname = makename();
10699 }
10700}
10701
10702/*
10703 * Returns true if the text contains nothing to expand (no dollar signs
10704 * or backquotes).
10705 */
10706static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010707noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010708{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010709 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010710
Denys Vlasenkocd716832009-11-28 22:14:02 +010010711 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010712 if (c == CTLQUOTEMARK)
10713 continue;
10714 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010715 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010716 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010717 return 0;
10718 }
10719 return 1;
10720}
10721
10722static void
10723parsefname(void)
10724{
10725 union node *n = redirnode;
10726
10727 if (readtoken() != TWORD)
10728 raise_error_unexpected_syntax(-1);
10729 if (n->type == NHERE) {
10730 struct heredoc *here = heredoc;
10731 struct heredoc *p;
10732 int i;
10733
10734 if (quoteflag == 0)
10735 n->type = NXHERE;
10736 TRACE(("Here document %d\n", n->type));
10737 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010738 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010739 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010740 here->eofmark = wordtext;
10741 here->next = NULL;
10742 if (heredoclist == NULL)
10743 heredoclist = here;
10744 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010745 for (p = heredoclist; p->next; p = p->next)
10746 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010747 p->next = here;
10748 }
10749 } else if (n->type == NTOFD || n->type == NFROMFD) {
10750 fixredir(n, wordtext, 0);
10751 } else {
10752 n->nfile.fname = makename();
10753 }
10754}
Eric Andersencb57d552001-06-28 07:25:16 +000010755
Eric Andersenc470f442003-07-28 09:56:35 +000010756static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010757simplecmd(void)
10758{
10759 union node *args, **app;
10760 union node *n = NULL;
10761 union node *vars, **vpp;
10762 union node **rpp, *redir;
10763 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010764#if ENABLE_ASH_BASH_COMPAT
10765 smallint double_brackets_flag = 0;
10766#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010767
10768 args = NULL;
10769 app = &args;
10770 vars = NULL;
10771 vpp = &vars;
10772 redir = NULL;
10773 rpp = &redir;
10774
10775 savecheckkwd = CHKALIAS;
10776 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010777 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010778 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010779 t = readtoken();
10780 switch (t) {
10781#if ENABLE_ASH_BASH_COMPAT
10782 case TAND: /* "&&" */
10783 case TOR: /* "||" */
10784 if (!double_brackets_flag) {
10785 tokpushback = 1;
10786 goto out;
10787 }
10788 wordtext = (char *) (t == TAND ? "-a" : "-o");
10789#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010790 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010791 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010792 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010793 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010794 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010795#if ENABLE_ASH_BASH_COMPAT
10796 if (strcmp("[[", wordtext) == 0)
10797 double_brackets_flag = 1;
10798 else if (strcmp("]]", wordtext) == 0)
10799 double_brackets_flag = 0;
10800#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010801 n->narg.backquote = backquotelist;
10802 if (savecheckkwd && isassignment(wordtext)) {
10803 *vpp = n;
10804 vpp = &n->narg.next;
10805 } else {
10806 *app = n;
10807 app = &n->narg.next;
10808 savecheckkwd = 0;
10809 }
10810 break;
10811 case TREDIR:
10812 *rpp = n = redirnode;
10813 rpp = &n->nfile.next;
10814 parsefname(); /* read name of redirection file */
10815 break;
10816 case TLP:
10817 if (args && app == &args->narg.next
10818 && !vars && !redir
10819 ) {
10820 struct builtincmd *bcmd;
10821 const char *name;
10822
10823 /* We have a function */
10824 if (readtoken() != TRP)
10825 raise_error_unexpected_syntax(TRP);
10826 name = n->narg.text;
10827 if (!goodname(name)
10828 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10829 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010830 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010831 }
10832 n->type = NDEFUN;
10833 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10834 n->narg.next = parse_command();
10835 return n;
10836 }
10837 /* fall through */
10838 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010839 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010840 goto out;
10841 }
10842 }
10843 out:
10844 *app = NULL;
10845 *vpp = NULL;
10846 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010847 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010848 n->type = NCMD;
10849 n->ncmd.args = args;
10850 n->ncmd.assign = vars;
10851 n->ncmd.redirect = redir;
10852 return n;
10853}
10854
10855static union node *
10856parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010857{
Eric Andersencb57d552001-06-28 07:25:16 +000010858 union node *n1, *n2;
10859 union node *ap, **app;
10860 union node *cp, **cpp;
10861 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000010862 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000010863 int t;
10864
10865 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000010866 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000010867
Eric Andersencb57d552001-06-28 07:25:16 +000010868 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000010869 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010870 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000010871 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000010872 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010873 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010874 n1->type = NIF;
10875 n1->nif.test = list(0);
10876 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010877 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010878 n1->nif.ifpart = list(0);
10879 n2 = n1;
10880 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010881 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010882 n2 = n2->nif.elsepart;
10883 n2->type = NIF;
10884 n2->nif.test = list(0);
10885 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010886 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010887 n2->nif.ifpart = list(0);
10888 }
10889 if (lasttoken == TELSE)
10890 n2->nif.elsepart = list(0);
10891 else {
10892 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010893 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010894 }
Eric Andersenc470f442003-07-28 09:56:35 +000010895 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000010896 break;
10897 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010898 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000010899 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010900 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010901 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000010902 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010903 got = readtoken();
10904 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010905 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000010906 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010907 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010908 }
10909 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010910 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010911 break;
10912 }
10913 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010914 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000010915 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010916 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000010917 n1->type = NFOR;
10918 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +000010919 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010920 if (readtoken() == TIN) {
10921 app = &ap;
10922 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010923 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010924 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010925 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010926 n2->narg.text = wordtext;
10927 n2->narg.backquote = backquotelist;
10928 *app = n2;
10929 app = &n2->narg.next;
10930 }
10931 *app = NULL;
10932 n1->nfor.args = ap;
10933 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010934 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000010935 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010936 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010937 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010938 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010939 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010940 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000010941 n1->nfor.args = n2;
10942 /*
10943 * Newline or semicolon here is optional (but note
10944 * that the original Bourne shell only allowed NL).
10945 */
10946 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010947 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010948 }
Eric Andersenc470f442003-07-28 09:56:35 +000010949 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010950 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010951 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010952 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010953 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010954 break;
10955 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010956 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000010957 n1->type = NCASE;
10958 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010959 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000010960 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010961 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010962 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010963 n2->narg.text = wordtext;
10964 n2->narg.backquote = backquotelist;
Eric Andersencb57d552001-06-28 07:25:16 +000010965 do {
Eric Andersenc470f442003-07-28 09:56:35 +000010966 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010967 } while (readtoken() == TNL);
10968 if (lasttoken != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010969 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000010970 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010971 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000010972 checkkwd = CHKNL | CHKKWD;
10973 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010974 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000010975 if (lasttoken == TLP)
10976 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010977 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000010978 cp->type = NCLIST;
10979 app = &cp->nclist.pattern;
10980 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010981 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010982 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010983 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010984 ap->narg.text = wordtext;
10985 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000010986 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000010987 break;
10988 app = &ap->narg.next;
10989 readtoken();
10990 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000010991 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000010992 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010993 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000010994 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010995
Eric Andersenc470f442003-07-28 09:56:35 +000010996 cpp = &cp->nclist.next;
10997
10998 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010999 t = readtoken();
11000 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011001 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011002 raise_error_unexpected_syntax(TENDCASE);
11003 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011004 }
Eric Andersenc470f442003-07-28 09:56:35 +000011005 }
Eric Andersencb57d552001-06-28 07:25:16 +000011006 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011007 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011008 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011009 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011010 n1->type = NSUBSHELL;
11011 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011012 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011013 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011014 break;
11015 case TBEGIN:
11016 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011017 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011018 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011019 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011020 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011021 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011022 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011023 }
11024
Eric Andersenc470f442003-07-28 09:56:35 +000011025 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011026 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011027
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011028 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011029 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011030 checkkwd = CHKKWD | CHKALIAS;
11031 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011032 while (readtoken() == TREDIR) {
11033 *rpp = n2 = redirnode;
11034 rpp = &n2->nfile.next;
11035 parsefname();
11036 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011037 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011038 *rpp = NULL;
11039 if (redir) {
11040 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011041 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011042 n2->type = NREDIR;
11043 n2->nredir.n = n1;
11044 n1 = n2;
11045 }
11046 n1->nredir.redirect = redir;
11047 }
Eric Andersencb57d552001-06-28 07:25:16 +000011048 return n1;
11049}
11050
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011051#if ENABLE_ASH_BASH_COMPAT
11052static int decode_dollar_squote(void)
11053{
11054 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11055 int c, cnt;
11056 char *p;
11057 char buf[4];
11058
11059 c = pgetc();
11060 p = strchr(C_escapes, c);
11061 if (p) {
11062 buf[0] = c;
11063 p = buf;
11064 cnt = 3;
11065 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11066 do {
11067 c = pgetc();
11068 *++p = c;
11069 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11070 pungetc();
11071 } else if (c == 'x') { /* \xHH */
11072 do {
11073 c = pgetc();
11074 *++p = c;
11075 } while (isxdigit(c) && --cnt);
11076 pungetc();
11077 if (cnt == 3) { /* \x but next char is "bad" */
11078 c = 'x';
11079 goto unrecognized;
11080 }
11081 } else { /* simple seq like \\ or \t */
11082 p++;
11083 }
11084 *p = '\0';
11085 p = buf;
11086 c = bb_process_escape_sequence((void*)&p);
11087 } else { /* unrecognized "\z": print both chars unless ' or " */
11088 if (c != '\'' && c != '"') {
11089 unrecognized:
11090 c |= 0x100; /* "please encode \, then me" */
11091 }
11092 }
11093 return c;
11094}
11095#endif
11096
Eric Andersencb57d552001-06-28 07:25:16 +000011097/*
11098 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11099 * is not NULL, read a here document. In the latter case, eofmark is the
11100 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011101 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011102 * is the first character of the input token or document.
11103 *
11104 * Because C does not have internal subroutines, I have simulated them
11105 * using goto's to implement the subroutine linkage. The following macros
11106 * will run code that appears at the end of readtoken1.
11107 */
Eric Andersen2870d962001-07-02 17:27:21 +000011108#define CHECKEND() {goto checkend; checkend_return:;}
11109#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11110#define PARSESUB() {goto parsesub; parsesub_return:;}
11111#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11112#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11113#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011114static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011115readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011116{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011117 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011118 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011119 char *out;
11120 int len;
11121 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011122 struct nodelist *bqlist;
11123 smallint quotef;
11124 smallint dblquote;
11125 smallint oldstyle;
11126 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011127#if ENABLE_ASH_EXPAND_PRMT
11128 smallint pssyntax; /* we are expanding a prompt string */
11129#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011130 int varnest; /* levels of variables expansion */
11131 int arinest; /* levels of arithmetic expansion */
11132 int parenlevel; /* levels of parens in arithmetic */
11133 int dqvarnest; /* levels of variables expansion within double quotes */
11134
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011135 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011136
Eric Andersencb57d552001-06-28 07:25:16 +000011137#if __GNUC__
11138 /* Avoid longjmp clobbering */
11139 (void) &out;
11140 (void) &quotef;
11141 (void) &dblquote;
11142 (void) &varnest;
11143 (void) &arinest;
11144 (void) &parenlevel;
11145 (void) &dqvarnest;
11146 (void) &oldstyle;
11147 (void) &prevsyntax;
11148 (void) &syntax;
11149#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011150 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011151 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011152 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011153 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011154#if ENABLE_ASH_EXPAND_PRMT
11155 pssyntax = (syntax == PSSYNTAX);
11156 if (pssyntax)
11157 syntax = DQSYNTAX;
11158#endif
11159 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011160 varnest = 0;
11161 arinest = 0;
11162 parenlevel = 0;
11163 dqvarnest = 0;
11164
11165 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011166 loop:
11167 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011168 CHECKEND(); /* set c to PEOF if at end of here document */
11169 for (;;) { /* until end of line or end of word */
11170 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11171 switch (SIT(c, syntax)) {
11172 case CNL: /* '\n' */
11173 if (syntax == BASESYNTAX)
11174 goto endword; /* exit outer loop */
11175 USTPUTC(c, out);
11176 g_parsefile->linno++;
11177 setprompt_if(doprompt, 2);
11178 c = pgetc();
11179 goto loop; /* continue outer loop */
11180 case CWORD:
11181 USTPUTC(c, out);
11182 break;
11183 case CCTL:
11184 if (eofmark == NULL || dblquote)
11185 USTPUTC(CTLESC, out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011186#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011187 if (c == '\\' && bash_dollar_squote) {
11188 c = decode_dollar_squote();
11189 if (c & 0x100) {
11190 USTPUTC('\\', out);
11191 c = (unsigned char)c;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011192 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011193 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011194#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011195 USTPUTC(c, out);
11196 break;
11197 case CBACK: /* backslash */
11198 c = pgetc_without_PEOA();
11199 if (c == PEOF) {
11200 USTPUTC(CTLESC, out);
11201 USTPUTC('\\', out);
11202 pungetc();
11203 } else if (c == '\n') {
11204 setprompt_if(doprompt, 2);
11205 } else {
11206#if ENABLE_ASH_EXPAND_PRMT
11207 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011208 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011209 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011210 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011211#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011212 /* Backslash is retained if we are in "str" and next char isn't special */
11213 if (dblquote
11214 && c != '\\'
11215 && c != '`'
11216 && c != '$'
11217 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011218 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011219 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011220 }
Ron Yorston549deab2015-05-18 09:57:51 +020011221 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011222 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011223 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011224 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011225 break;
11226 case CSQUOTE:
11227 syntax = SQSYNTAX;
11228 quotemark:
11229 if (eofmark == NULL) {
11230 USTPUTC(CTLQUOTEMARK, out);
11231 }
11232 break;
11233 case CDQUOTE:
11234 syntax = DQSYNTAX;
11235 dblquote = 1;
11236 goto quotemark;
11237 case CENDQUOTE:
11238 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011239 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011240 USTPUTC(c, out);
11241 } else {
11242 if (dqvarnest == 0) {
11243 syntax = BASESYNTAX;
11244 dblquote = 0;
11245 }
11246 quotef = 1;
11247 goto quotemark;
11248 }
11249 break;
11250 case CVAR: /* '$' */
11251 PARSESUB(); /* parse substitution */
11252 break;
11253 case CENDVAR: /* '}' */
11254 if (varnest > 0) {
11255 varnest--;
11256 if (dqvarnest > 0) {
11257 dqvarnest--;
11258 }
11259 c = CTLENDVAR;
11260 }
11261 USTPUTC(c, out);
11262 break;
11263#if ENABLE_SH_MATH_SUPPORT
11264 case CLP: /* '(' in arithmetic */
11265 parenlevel++;
11266 USTPUTC(c, out);
11267 break;
11268 case CRP: /* ')' in arithmetic */
11269 if (parenlevel > 0) {
11270 parenlevel--;
11271 } else {
11272 if (pgetc() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011273 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011274 if (--arinest == 0) {
11275 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011276 }
11277 } else {
11278 /*
11279 * unbalanced parens
11280 * (don't 2nd guess - no error)
11281 */
11282 pungetc();
11283 }
11284 }
11285 USTPUTC(c, out);
11286 break;
11287#endif
11288 case CBQUOTE: /* '`' */
11289 PARSEBACKQOLD();
11290 break;
11291 case CENDFILE:
11292 goto endword; /* exit outer loop */
11293 case CIGN:
11294 break;
11295 default:
11296 if (varnest == 0) {
11297#if ENABLE_ASH_BASH_COMPAT
11298 if (c == '&') {
11299 if (pgetc() == '>')
11300 c = 0x100 + '>'; /* flag &> */
11301 pungetc();
11302 }
11303#endif
11304 goto endword; /* exit outer loop */
11305 }
11306 IF_ASH_ALIAS(if (c != PEOA))
11307 USTPUTC(c, out);
11308 }
11309 c = pgetc_fast();
11310 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011311 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011312
Mike Frysinger98c52642009-04-02 10:02:37 +000011313#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011314 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011315 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011316#endif
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011317 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011318 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011319 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011320 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011321 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011322 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011323 }
11324 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011325 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011326 out = stackblock();
11327 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011328 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011329 && quotef == 0
11330 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011331 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011332 PARSEREDIR(); /* passed as params: out, c */
11333 lasttoken = TREDIR;
11334 return lasttoken;
11335 }
11336 /* else: non-number X seen, interpret it
11337 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011338 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011339 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011340 }
11341 quoteflag = quotef;
11342 backquotelist = bqlist;
11343 grabstackblock(len);
11344 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011345 lasttoken = TWORD;
11346 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011347/* end of readtoken routine */
11348
Eric Andersencb57d552001-06-28 07:25:16 +000011349/*
11350 * Check to see whether we are at the end of the here document. When this
11351 * is called, c is set to the first character of the next input line. If
11352 * we are at the end of the here document, this routine sets the c to PEOF.
11353 */
Eric Andersenc470f442003-07-28 09:56:35 +000011354checkend: {
11355 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011356#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011357 if (c == PEOA)
11358 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011359#endif
11360 if (striptabs) {
11361 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011362 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011363 }
Eric Andersenc470f442003-07-28 09:56:35 +000011364 }
11365 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011366 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011367 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011368
Eric Andersenc470f442003-07-28 09:56:35 +000011369 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011370 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11371 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011372 if (*p == '\n' && *q == '\0') {
11373 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011374 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011375 needprompt = doprompt;
11376 } else {
11377 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011378 }
11379 }
11380 }
11381 }
Eric Andersenc470f442003-07-28 09:56:35 +000011382 goto checkend_return;
11383}
Eric Andersencb57d552001-06-28 07:25:16 +000011384
Eric Andersencb57d552001-06-28 07:25:16 +000011385/*
11386 * Parse a redirection operator. The variable "out" points to a string
11387 * specifying the fd to be redirected. The variable "c" contains the
11388 * first character of the redirection operator.
11389 */
Eric Andersenc470f442003-07-28 09:56:35 +000011390parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011391 /* out is already checked to be a valid number or "" */
11392 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011393 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011394
Denis Vlasenko597906c2008-02-20 16:38:54 +000011395 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011396 if (c == '>') {
11397 np->nfile.fd = 1;
11398 c = pgetc();
11399 if (c == '>')
11400 np->type = NAPPEND;
11401 else if (c == '|')
11402 np->type = NCLOBBER;
11403 else if (c == '&')
11404 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011405 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011406 else {
11407 np->type = NTO;
11408 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011409 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011410 }
11411#if ENABLE_ASH_BASH_COMPAT
11412 else if (c == 0x100 + '>') { /* this flags &> redirection */
11413 np->nfile.fd = 1;
11414 pgetc(); /* this is '>', no need to check */
11415 np->type = NTO2;
11416 }
11417#endif
11418 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011419 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011420 c = pgetc();
11421 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011422 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011423 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011424 np = stzalloc(sizeof(struct nhere));
11425 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011426 }
11427 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011428 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011429 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011430 c = pgetc();
11431 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011432 heredoc->striptabs = 1;
11433 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011434 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011435 pungetc();
11436 }
11437 break;
11438
11439 case '&':
11440 np->type = NFROMFD;
11441 break;
11442
11443 case '>':
11444 np->type = NFROMTO;
11445 break;
11446
11447 default:
11448 np->type = NFROM;
11449 pungetc();
11450 break;
11451 }
Eric Andersencb57d552001-06-28 07:25:16 +000011452 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011453 if (fd >= 0)
11454 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011455 redirnode = np;
11456 goto parseredir_return;
11457}
Eric Andersencb57d552001-06-28 07:25:16 +000011458
Eric Andersencb57d552001-06-28 07:25:16 +000011459/*
11460 * Parse a substitution. At this point, we have read the dollar sign
11461 * and nothing else.
11462 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011463
11464/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11465 * (assuming ascii char codes, as the original implementation did) */
11466#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011467 (((unsigned)(c) - 33 < 32) \
11468 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011469parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011470 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011471 int typeloc;
11472 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011473
Eric Andersenc470f442003-07-28 09:56:35 +000011474 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011475 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011476 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011477 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011478#if ENABLE_ASH_BASH_COMPAT
11479 if (c == '\'')
11480 bash_dollar_squote = 1;
11481 else
11482#endif
11483 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011484 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011485 } else if (c == '(') {
11486 /* $(command) or $((arith)) */
Eric Andersenc470f442003-07-28 09:56:35 +000011487 if (pgetc() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011488#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011489 PARSEARITH();
11490#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011491 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011492#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011493 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011494 pungetc();
11495 PARSEBACKQNEW();
11496 }
11497 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011498 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011499 USTPUTC(CTLVAR, out);
11500 typeloc = out - (char *)stackblock();
11501 USTPUTC(VSNORMAL, out);
11502 subtype = VSNORMAL;
11503 if (c == '{') {
11504 c = pgetc();
11505 if (c == '#') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011506 c = pgetc();
11507 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011508 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011509 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011510 subtype = VSLENGTH; /* ${#VAR} */
11511 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011512 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011513 }
Eric Andersenc470f442003-07-28 09:56:35 +000011514 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011515 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011516 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011517 do {
11518 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011519 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011520 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011521 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011522 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011523 do {
11524 STPUTC(c, out);
11525 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011526 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011527 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011528 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011529 USTPUTC(c, out);
11530 c = pgetc();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011531 } else {
11532 badsub:
11533 raise_error_syntax("bad substitution");
11534 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011535 if (c != '}' && subtype == VSLENGTH) {
11536 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011537 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011538 }
Eric Andersencb57d552001-06-28 07:25:16 +000011539
Eric Andersenc470f442003-07-28 09:56:35 +000011540 STPUTC('=', out);
11541 flags = 0;
11542 if (subtype == 0) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011543 /* ${VAR...} but not $VAR or ${#VAR} */
11544 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011545 switch (c) {
11546 case ':':
Eric Andersenc470f442003-07-28 09:56:35 +000011547 c = pgetc();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011548#if ENABLE_ASH_BASH_COMPAT
11549 if (c == ':' || c == '$' || isdigit(c)) {
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011550//TODO: support more general format ${v:EXPR:EXPR},
11551// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011552 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011553 pungetc();
11554 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011555 }
11556#endif
11557 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011558 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011559 default: {
11560 static const char types[] ALIGN1 = "}-+?=";
11561 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011562 if (p == NULL)
11563 goto badsub;
11564 subtype = p - types + VSNORMAL;
11565 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011566 }
Eric Andersenc470f442003-07-28 09:56:35 +000011567 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011568 case '#': {
11569 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011570 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011571 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011572 if (c != cc)
11573 goto do_pungetc;
11574 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011575 break;
11576 }
11577#if ENABLE_ASH_BASH_COMPAT
11578 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011579 /* ${v/[/]pattern/repl} */
11580//TODO: encode pattern and repl separately.
11581// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011582 subtype = VSREPLACE;
11583 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011584 if (c != '/')
11585 goto do_pungetc;
11586 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011587 break;
11588#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011589 }
Eric Andersenc470f442003-07-28 09:56:35 +000011590 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011591 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011592 pungetc();
11593 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011594 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011595 if (subtype != VSNORMAL) {
11596 varnest++;
Ron Yorston7e4ed262015-05-18 09:54:43 +020011597 if (dblquote) {
Eric Andersenc470f442003-07-28 09:56:35 +000011598 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011599 }
11600 }
11601 }
Eric Andersenc470f442003-07-28 09:56:35 +000011602 goto parsesub_return;
11603}
Eric Andersencb57d552001-06-28 07:25:16 +000011604
Eric Andersencb57d552001-06-28 07:25:16 +000011605/*
11606 * Called to parse command substitutions. Newstyle is set if the command
11607 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11608 * list of commands (passed by reference), and savelen is the number of
11609 * characters on the top of the stack which must be preserved.
11610 */
Eric Andersenc470f442003-07-28 09:56:35 +000011611parsebackq: {
11612 struct nodelist **nlpp;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011613 smallint savepbq;
Eric Andersenc470f442003-07-28 09:56:35 +000011614 union node *n;
11615 char *volatile str;
11616 struct jmploc jmploc;
11617 struct jmploc *volatile savehandler;
11618 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011619 smallint saveprompt = 0;
11620
Eric Andersencb57d552001-06-28 07:25:16 +000011621#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000011622 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000011623#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011624 savepbq = parsebackquote;
11625 if (setjmp(jmploc.loc)) {
Denis Vlasenko60818682007-09-28 22:07:23 +000011626 free(str);
Eric Andersenc470f442003-07-28 09:56:35 +000011627 parsebackquote = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011628 exception_handler = savehandler;
11629 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000011630 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011631 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011632 str = NULL;
11633 savelen = out - (char *)stackblock();
11634 if (savelen > 0) {
11635 str = ckmalloc(savelen);
11636 memcpy(str, stackblock(), savelen);
11637 }
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011638 savehandler = exception_handler;
11639 exception_handler = &jmploc;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011640 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000011641 if (oldstyle) {
11642 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011643 * treatment to some slashes, and then push the string and
11644 * reread it as input, interpreting it normally.
11645 */
Eric Andersenc470f442003-07-28 09:56:35 +000011646 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011647 size_t psavelen;
11648 char *pstr;
11649
Eric Andersenc470f442003-07-28 09:56:35 +000011650 STARTSTACKSTR(pout);
11651 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011652 int pc;
11653
11654 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011655 pc = pgetc();
11656 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011657 case '`':
11658 goto done;
11659
11660 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011661 pc = pgetc();
11662 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011663 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011664 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011665 /*
11666 * If eating a newline, avoid putting
11667 * the newline into the new character
11668 * stream (via the STPUTC after the
11669 * switch).
11670 */
11671 continue;
11672 }
11673 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011674 && (!dblquote || pc != '"')
11675 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011676 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011677 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011678 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011679 break;
11680 }
11681 /* fall through */
11682
11683 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011684 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011685 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011686 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011687
11688 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011689 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011690 needprompt = doprompt;
11691 break;
11692
11693 default:
11694 break;
11695 }
11696 STPUTC(pc, pout);
11697 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011698 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011699 STPUTC('\0', pout);
11700 psavelen = pout - (char *)stackblock();
11701 if (psavelen > 0) {
11702 pstr = grabstackstr(pout);
11703 setinputstring(pstr);
11704 }
11705 }
11706 nlpp = &bqlist;
11707 while (*nlpp)
11708 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011709 *nlpp = stzalloc(sizeof(**nlpp));
11710 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011711 parsebackquote = oldstyle;
11712
11713 if (oldstyle) {
11714 saveprompt = doprompt;
11715 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011716 }
11717
Eric Andersenc470f442003-07-28 09:56:35 +000011718 n = list(2);
11719
11720 if (oldstyle)
11721 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011722 else if (readtoken() != TRP)
11723 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011724
11725 (*nlpp)->n = n;
11726 if (oldstyle) {
11727 /*
11728 * Start reading from old file again, ignoring any pushed back
11729 * tokens left from the backquote parsing
11730 */
11731 popfile();
11732 tokpushback = 0;
11733 }
11734 while (stackblocksize() <= savelen)
11735 growstackblock();
11736 STARTSTACKSTR(out);
11737 if (str) {
11738 memcpy(out, str, savelen);
11739 STADJUST(savelen, out);
Denis Vlasenkob012b102007-02-19 22:43:01 +000011740 INT_OFF;
11741 free(str);
Eric Andersenc470f442003-07-28 09:56:35 +000011742 str = NULL;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011743 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000011744 }
11745 parsebackquote = savepbq;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011746 exception_handler = savehandler;
Ron Yorston549deab2015-05-18 09:57:51 +020011747 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011748 if (oldstyle)
11749 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011750 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011751}
11752
Mike Frysinger98c52642009-04-02 10:02:37 +000011753#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011754/*
11755 * Parse an arithmetic expansion (indicate start of one and set state)
11756 */
Eric Andersenc470f442003-07-28 09:56:35 +000011757parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011758 if (++arinest == 1) {
11759 prevsyntax = syntax;
11760 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011761 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011762 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011763 goto parsearith_return;
11764}
11765#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011766
Eric Andersenc470f442003-07-28 09:56:35 +000011767} /* end of readtoken */
11768
Eric Andersencb57d552001-06-28 07:25:16 +000011769/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011770 * Read the next input token.
11771 * If the token is a word, we set backquotelist to the list of cmds in
11772 * backquotes. We set quoteflag to true if any part of the word was
11773 * quoted.
11774 * If the token is TREDIR, then we set redirnode to a structure containing
11775 * the redirection.
11776 * In all cases, the variable startlinno is set to the number of the line
11777 * on which the token starts.
11778 *
11779 * [Change comment: here documents and internal procedures]
11780 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11781 * word parsing code into a separate routine. In this case, readtoken
11782 * doesn't need to have any internal procedures, but parseword does.
11783 * We could also make parseoperator in essence the main routine, and
11784 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011785 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011786#define NEW_xxreadtoken
11787#ifdef NEW_xxreadtoken
11788/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011789static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011790 '\n', '(', ')', /* singles */
11791 '&', '|', ';', /* doubles */
11792 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011793};
Eric Andersencb57d552001-06-28 07:25:16 +000011794
Denis Vlasenko834dee72008-10-07 09:18:30 +000011795#define xxreadtoken_singles 3
11796#define xxreadtoken_doubles 3
11797
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011798static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011799 TNL, TLP, TRP, /* only single occurrence allowed */
11800 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11801 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011802 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011803};
11804
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011805static int
11806xxreadtoken(void)
11807{
11808 int c;
11809
11810 if (tokpushback) {
11811 tokpushback = 0;
11812 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011813 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011814 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011815 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011816 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011817 c = pgetc_fast();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011818 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011819 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011820
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011821 if (c == '#') {
11822 while ((c = pgetc()) != '\n' && c != PEOF)
11823 continue;
11824 pungetc();
11825 } else if (c == '\\') {
11826 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011827 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011828 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011829 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011830 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011831 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011832 } else {
11833 const char *p;
11834
11835 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11836 if (c != PEOF) {
11837 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011838 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011839 needprompt = doprompt;
11840 }
11841
11842 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011843 if (p == NULL)
11844 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011845
Denis Vlasenko834dee72008-10-07 09:18:30 +000011846 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11847 int cc = pgetc();
11848 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011849 p += xxreadtoken_doubles + 1;
11850 } else {
11851 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011852#if ENABLE_ASH_BASH_COMPAT
11853 if (c == '&' && cc == '>') /* &> */
11854 break; /* return readtoken1(...) */
11855#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011856 }
11857 }
11858 }
11859 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11860 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011861 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011862 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011863
11864 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011865}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011866#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011867#define RETURN(token) return lasttoken = token
11868static int
11869xxreadtoken(void)
11870{
11871 int c;
11872
11873 if (tokpushback) {
11874 tokpushback = 0;
11875 return lasttoken;
11876 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011877 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011878 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011879 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011880 c = pgetc_fast();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011881 switch (c) {
11882 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011883 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011884 continue;
11885 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011886 while ((c = pgetc()) != '\n' && c != PEOF)
11887 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011888 pungetc();
11889 continue;
11890 case '\\':
11891 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011892 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011893 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011894 continue;
11895 }
11896 pungetc();
11897 goto breakloop;
11898 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011899 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011900 needprompt = doprompt;
11901 RETURN(TNL);
11902 case PEOF:
11903 RETURN(TEOF);
11904 case '&':
11905 if (pgetc() == '&')
11906 RETURN(TAND);
11907 pungetc();
11908 RETURN(TBACKGND);
11909 case '|':
11910 if (pgetc() == '|')
11911 RETURN(TOR);
11912 pungetc();
11913 RETURN(TPIPE);
11914 case ';':
11915 if (pgetc() == ';')
11916 RETURN(TENDCASE);
11917 pungetc();
11918 RETURN(TSEMI);
11919 case '(':
11920 RETURN(TLP);
11921 case ')':
11922 RETURN(TRP);
11923 default:
11924 goto breakloop;
11925 }
11926 }
11927 breakloop:
11928 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11929#undef RETURN
11930}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011931#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011932
11933static int
11934readtoken(void)
11935{
11936 int t;
11937#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011938 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011939#endif
11940
11941#if ENABLE_ASH_ALIAS
11942 top:
11943#endif
11944
11945 t = xxreadtoken();
11946
11947 /*
11948 * eat newlines
11949 */
11950 if (checkkwd & CHKNL) {
11951 while (t == TNL) {
11952 parseheredoc();
11953 t = xxreadtoken();
11954 }
11955 }
11956
11957 if (t != TWORD || quoteflag) {
11958 goto out;
11959 }
11960
11961 /*
11962 * check for keywords
11963 */
11964 if (checkkwd & CHKKWD) {
11965 const char *const *pp;
11966
11967 pp = findkwd(wordtext);
11968 if (pp) {
11969 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011970 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011971 goto out;
11972 }
11973 }
11974
11975 if (checkkwd & CHKALIAS) {
11976#if ENABLE_ASH_ALIAS
11977 struct alias *ap;
11978 ap = lookupalias(wordtext, 1);
11979 if (ap != NULL) {
11980 if (*ap->val) {
11981 pushstring(ap->val, ap);
11982 }
11983 goto top;
11984 }
11985#endif
11986 }
11987 out:
11988 checkkwd = 0;
11989#if DEBUG
11990 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011991 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011992 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011993 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011994#endif
11995 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000011996}
11997
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011998static char
Denys Vlasenko7e661022015-02-05 21:00:17 +010011999nexttoken_ends_list(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012000{
12001 int t;
12002
12003 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012004 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012005 return tokname_array[t][0];
12006}
Eric Andersencb57d552001-06-28 07:25:16 +000012007
12008/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012009 * Read and parse a command. Returns NODE_EOF on end of file.
12010 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012011 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012012static union node *
12013parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012014{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012015 int t;
Eric Andersencb57d552001-06-28 07:25:16 +000012016
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012017 tokpushback = 0;
12018 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012019 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012020 needprompt = 0;
12021 t = readtoken();
12022 if (t == TEOF)
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012023 return NODE_EOF;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012024 if (t == TNL)
12025 return NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012026 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012027 return list(1);
12028}
12029
12030/*
12031 * Input any here documents.
12032 */
12033static void
12034parseheredoc(void)
12035{
12036 struct heredoc *here;
12037 union node *n;
12038
12039 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012040 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012041
12042 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012043 setprompt_if(needprompt, 2);
12044 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012045 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012046 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012047 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012048 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012049 n->narg.text = wordtext;
12050 n->narg.backquote = backquotelist;
12051 here->here->nhere.doc = n;
12052 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012053 }
Eric Andersencb57d552001-06-28 07:25:16 +000012054}
12055
12056
12057/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012058 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012059 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012060#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012061static const char *
12062expandstr(const char *ps)
12063{
12064 union node n;
12065
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012066 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12067 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012068 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012069 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012070 popfile();
12071
12072 n.narg.type = NARG;
12073 n.narg.next = NULL;
12074 n.narg.text = wordtext;
12075 n.narg.backquote = backquotelist;
12076
Ron Yorston549deab2015-05-18 09:57:51 +020012077 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012078 return stackblock();
12079}
12080#endif
12081
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012082/*
12083 * Execute a command or commands contained in a string.
12084 */
12085static int
12086evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012087{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012088 union node *n;
12089 struct stackmark smark;
12090 int skip;
12091
12092 setinputstring(s);
12093 setstackmark(&smark);
12094
12095 skip = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012096 while ((n = parsecmd(0)) != NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012097 evaltree(n, 0);
12098 popstackmark(&smark);
12099 skip = evalskip;
12100 if (skip)
12101 break;
12102 }
12103 popfile();
12104
12105 skip &= mask;
12106 evalskip = skip;
12107 return skip;
Eric Andersenc470f442003-07-28 09:56:35 +000012108}
12109
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012110/*
12111 * The eval command.
12112 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012113static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012114evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012115{
12116 char *p;
12117 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012118
Denis Vlasenko68404f12008-03-17 09:00:54 +000012119 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012120 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012121 argv += 2;
12122 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012123 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012124 for (;;) {
12125 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012126 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012127 if (p == NULL)
12128 break;
12129 STPUTC(' ', concat);
12130 }
12131 STPUTC('\0', concat);
12132 p = grabstackstr(concat);
12133 }
12134 evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012135 }
12136 return exitstatus;
12137}
12138
12139/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012140 * Read and execute commands.
12141 * "Top" is nonzero for the top level command loop;
12142 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012143 */
12144static int
12145cmdloop(int top)
12146{
12147 union node *n;
12148 struct stackmark smark;
12149 int inter;
12150 int numeof = 0;
12151
12152 TRACE(("cmdloop(%d) called\n", top));
12153 for (;;) {
12154 int skip;
12155
12156 setstackmark(&smark);
12157#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012158 if (doing_jobctl)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012159 showjobs(stderr, SHOW_CHANGED);
12160#endif
12161 inter = 0;
12162 if (iflag && top) {
12163 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012164 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012165 }
12166 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012167#if DEBUG
12168 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012169 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012170#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012171 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012172 if (!top || numeof >= 50)
12173 break;
12174 if (!stoppedjobs()) {
12175 if (!Iflag)
12176 break;
12177 out2str("\nUse \"exit\" to leave shell.\n");
12178 }
12179 numeof++;
12180 } else if (nflag == 0) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012181 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12182 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012183 numeof = 0;
12184 evaltree(n, 0);
12185 }
12186 popstackmark(&smark);
12187 skip = evalskip;
12188
12189 if (skip) {
12190 evalskip = 0;
12191 return skip & SKIPEVAL;
12192 }
12193 }
12194 return 0;
12195}
12196
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012197/*
12198 * Take commands from a file. To be compatible we should do a path
12199 * search for the file, which is necessary to find sub-commands.
12200 */
12201static char *
12202find_dot_file(char *name)
12203{
12204 char *fullname;
12205 const char *path = pathval();
12206 struct stat statb;
12207
12208 /* don't try this for absolute or relative paths */
12209 if (strchr(name, '/'))
12210 return name;
12211
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012212 /* IIRC standards do not say whether . is to be searched.
12213 * And it is even smaller this way, making it unconditional for now:
12214 */
12215 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12216 fullname = name;
12217 goto try_cur_dir;
12218 }
12219
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012220 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012221 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012222 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12223 /*
12224 * Don't bother freeing here, since it will
12225 * be freed by the caller.
12226 */
12227 return fullname;
12228 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012229 if (fullname != name)
12230 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012231 }
12232
12233 /* not found in the PATH */
12234 ash_msg_and_raise_error("%s: not found", name);
12235 /* NOTREACHED */
12236}
12237
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012238static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012239dotcmd(int argc, char **argv)
12240{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012241 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012242 struct strlist *sp;
12243 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012244
12245 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012246 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012247
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012248 if (!argv[1]) {
12249 /* bash says: "bash: .: filename argument required" */
12250 return 2; /* bash compat */
12251 }
12252
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012253 /* "false; . empty_file; echo $?" should print 0, not 1: */
12254 exitstatus = 0;
12255
Denys Vlasenko091f8312013-03-17 14:25:22 +010012256 /* This aborts if file isn't found, which is POSIXly correct.
12257 * bash returns exitcode 1 instead.
12258 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012259 fullname = find_dot_file(argv[1]);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012260 argv += 2;
12261 argc -= 2;
12262 if (argc) { /* argc > 0, argv[0] != NULL */
12263 saveparam = shellparam;
12264 shellparam.malloced = 0;
12265 shellparam.nparam = argc;
12266 shellparam.p = argv;
12267 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012268
Denys Vlasenko091f8312013-03-17 14:25:22 +010012269 /* This aborts if file can't be opened, which is POSIXly correct.
12270 * bash returns exitcode 1 instead.
12271 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012272 setinputfile(fullname, INPUT_PUSH_FILE);
12273 commandname = fullname;
12274 cmdloop(0);
12275 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012276
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012277 if (argc) {
12278 freeparam(&shellparam);
12279 shellparam = saveparam;
12280 };
12281
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012282 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012283}
12284
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012285static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012286exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012287{
12288 if (stoppedjobs())
12289 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012290 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012291 exitstatus = number(argv[1]);
12292 raise_exception(EXEXIT);
12293 /* NOTREACHED */
12294}
12295
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012296/*
12297 * Read a file containing shell functions.
12298 */
12299static void
12300readcmdfile(char *name)
12301{
12302 setinputfile(name, INPUT_PUSH_FILE);
12303 cmdloop(0);
12304 popfile();
12305}
12306
12307
Denis Vlasenkocc571512007-02-23 21:10:35 +000012308/* ============ find_command inplementation */
12309
12310/*
12311 * Resolve a command name. If you change this routine, you may have to
12312 * change the shellexec routine as well.
12313 */
12314static void
12315find_command(char *name, struct cmdentry *entry, int act, const char *path)
12316{
12317 struct tblentry *cmdp;
12318 int idx;
12319 int prev;
12320 char *fullname;
12321 struct stat statb;
12322 int e;
12323 int updatetbl;
12324 struct builtincmd *bcmd;
12325
12326 /* If name contains a slash, don't use PATH or hash table */
12327 if (strchr(name, '/') != NULL) {
12328 entry->u.index = -1;
12329 if (act & DO_ABS) {
12330 while (stat(name, &statb) < 0) {
12331#ifdef SYSV
12332 if (errno == EINTR)
12333 continue;
12334#endif
12335 entry->cmdtype = CMDUNKNOWN;
12336 return;
12337 }
12338 }
12339 entry->cmdtype = CMDNORMAL;
12340 return;
12341 }
12342
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012343/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012344
12345 updatetbl = (path == pathval());
12346 if (!updatetbl) {
12347 act |= DO_ALTPATH;
12348 if (strstr(path, "%builtin") != NULL)
12349 act |= DO_ALTBLTIN;
12350 }
12351
12352 /* If name is in the table, check answer will be ok */
12353 cmdp = cmdlookup(name, 0);
12354 if (cmdp != NULL) {
12355 int bit;
12356
12357 switch (cmdp->cmdtype) {
12358 default:
12359#if DEBUG
12360 abort();
12361#endif
12362 case CMDNORMAL:
12363 bit = DO_ALTPATH;
12364 break;
12365 case CMDFUNCTION:
12366 bit = DO_NOFUNC;
12367 break;
12368 case CMDBUILTIN:
12369 bit = DO_ALTBLTIN;
12370 break;
12371 }
12372 if (act & bit) {
12373 updatetbl = 0;
12374 cmdp = NULL;
12375 } else if (cmdp->rehash == 0)
12376 /* if not invalidated by cd, we're done */
12377 goto success;
12378 }
12379
12380 /* If %builtin not in path, check for builtin next */
12381 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012382 if (bcmd) {
12383 if (IS_BUILTIN_REGULAR(bcmd))
12384 goto builtin_success;
12385 if (act & DO_ALTPATH) {
12386 if (!(act & DO_ALTBLTIN))
12387 goto builtin_success;
12388 } else if (builtinloc <= 0) {
12389 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012390 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012391 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012392
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012393#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012394 {
12395 int applet_no = find_applet_by_name(name);
12396 if (applet_no >= 0) {
12397 entry->cmdtype = CMDNORMAL;
12398 entry->u.index = -2 - applet_no;
12399 return;
12400 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012401 }
12402#endif
12403
Denis Vlasenkocc571512007-02-23 21:10:35 +000012404 /* We have to search path. */
12405 prev = -1; /* where to start */
12406 if (cmdp && cmdp->rehash) { /* doing a rehash */
12407 if (cmdp->cmdtype == CMDBUILTIN)
12408 prev = builtinloc;
12409 else
12410 prev = cmdp->param.index;
12411 }
12412
12413 e = ENOENT;
12414 idx = -1;
12415 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012416 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012417 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012418 /* NB: code below will still use fullname
12419 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012420 idx++;
12421 if (pathopt) {
12422 if (prefix(pathopt, "builtin")) {
12423 if (bcmd)
12424 goto builtin_success;
12425 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012426 }
12427 if ((act & DO_NOFUNC)
12428 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012429 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012430 continue;
12431 }
12432 }
12433 /* if rehash, don't redo absolute path names */
12434 if (fullname[0] == '/' && idx <= prev) {
12435 if (idx < prev)
12436 continue;
12437 TRACE(("searchexec \"%s\": no change\n", name));
12438 goto success;
12439 }
12440 while (stat(fullname, &statb) < 0) {
12441#ifdef SYSV
12442 if (errno == EINTR)
12443 continue;
12444#endif
12445 if (errno != ENOENT && errno != ENOTDIR)
12446 e = errno;
12447 goto loop;
12448 }
12449 e = EACCES; /* if we fail, this will be the error */
12450 if (!S_ISREG(statb.st_mode))
12451 continue;
12452 if (pathopt) { /* this is a %func directory */
12453 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012454 /* NB: stalloc will return space pointed by fullname
12455 * (because we don't have any intervening allocations
12456 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012457 readcmdfile(fullname);
12458 cmdp = cmdlookup(name, 0);
12459 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12460 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12461 stunalloc(fullname);
12462 goto success;
12463 }
12464 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12465 if (!updatetbl) {
12466 entry->cmdtype = CMDNORMAL;
12467 entry->u.index = idx;
12468 return;
12469 }
12470 INT_OFF;
12471 cmdp = cmdlookup(name, 1);
12472 cmdp->cmdtype = CMDNORMAL;
12473 cmdp->param.index = idx;
12474 INT_ON;
12475 goto success;
12476 }
12477
12478 /* We failed. If there was an entry for this command, delete it */
12479 if (cmdp && updatetbl)
12480 delete_cmd_entry();
12481 if (act & DO_ERR)
12482 ash_msg("%s: %s", name, errmsg(e, "not found"));
12483 entry->cmdtype = CMDUNKNOWN;
12484 return;
12485
12486 builtin_success:
12487 if (!updatetbl) {
12488 entry->cmdtype = CMDBUILTIN;
12489 entry->u.cmd = bcmd;
12490 return;
12491 }
12492 INT_OFF;
12493 cmdp = cmdlookup(name, 1);
12494 cmdp->cmdtype = CMDBUILTIN;
12495 cmdp->param.cmd = bcmd;
12496 INT_ON;
12497 success:
12498 cmdp->rehash = 0;
12499 entry->cmdtype = cmdp->cmdtype;
12500 entry->u = cmdp->param;
12501}
12502
12503
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012504/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012505
Eric Andersencb57d552001-06-28 07:25:16 +000012506/*
Eric Andersencb57d552001-06-28 07:25:16 +000012507 * The trap builtin.
12508 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012509static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012510trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012511{
12512 char *action;
12513 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012514 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012515
Eric Andersenc470f442003-07-28 09:56:35 +000012516 nextopt(nullstr);
12517 ap = argptr;
12518 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012519 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012520 char *tr = trap_ptr[signo];
12521 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012522 /* note: bash adds "SIG", but only if invoked
12523 * as "bash". If called as "sh", or if set -o posix,
12524 * then it prints short signal names.
12525 * We are printing short names: */
12526 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012527 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012528 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012529 /* trap_ptr != trap only if we are in special-cased `trap` code.
12530 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012531 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012532 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012533 }
12534 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012535 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012536 if (trap_ptr != trap) {
12537 free(trap_ptr);
12538 trap_ptr = trap;
12539 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012540 */
Eric Andersencb57d552001-06-28 07:25:16 +000012541 return 0;
12542 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012543
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012544 action = NULL;
12545 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012546 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012547 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012548 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012549 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012550 if (signo < 0) {
12551 /* Mimic bash message exactly */
12552 ash_msg("%s: invalid signal specification", *ap);
12553 exitcode = 1;
12554 goto next;
12555 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012556 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012557 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012558 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012559 action = NULL;
12560 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012561 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012562 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012563 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012564 if (action)
12565 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012566 trap[signo] = action;
12567 if (signo != 0)
12568 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012569 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012570 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012571 ap++;
12572 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012573 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012574}
12575
Eric Andersenc470f442003-07-28 09:56:35 +000012576
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012577/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012578
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012579#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012580static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012581helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012582{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012583 unsigned col;
12584 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012585
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012586 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012587 "Built-in commands:\n"
12588 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012589 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012590 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012591 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012592 if (col > 60) {
12593 out1fmt("\n");
12594 col = 0;
12595 }
12596 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012597# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012598 {
12599 const char *a = applet_names;
12600 while (*a) {
12601 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12602 if (col > 60) {
12603 out1fmt("\n");
12604 col = 0;
12605 }
12606 a += strlen(a) + 1;
Eric Andersenc470f442003-07-28 09:56:35 +000012607 }
12608 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012609# endif
Eric Andersenc470f442003-07-28 09:56:35 +000012610 out1fmt("\n\n");
12611 return EXIT_SUCCESS;
12612}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012613#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012614
Flemming Madsend96ffda2013-04-07 18:47:24 +020012615#if MAX_HISTORY
12616static int FAST_FUNC
12617historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12618{
12619 show_history(line_input_state);
12620 return EXIT_SUCCESS;
12621}
12622#endif
12623
Eric Andersencb57d552001-06-28 07:25:16 +000012624/*
Eric Andersencb57d552001-06-28 07:25:16 +000012625 * The export and readonly commands.
12626 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012627static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012628exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012629{
12630 struct var *vp;
12631 char *name;
12632 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012633 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012634 char opt;
12635 int flag;
12636 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012637
Denys Vlasenkod5275882012-10-01 13:41:17 +020012638 /* "readonly" in bash accepts, but ignores -n.
12639 * We do the same: it saves a conditional in nextopt's param.
12640 */
12641 flag_off = 0;
12642 while ((opt = nextopt("np")) != '\0') {
12643 if (opt == 'n')
12644 flag_off = VEXPORT;
12645 }
12646 flag = VEXPORT;
12647 if (argv[0][0] == 'r') {
12648 flag = VREADONLY;
12649 flag_off = 0; /* readonly ignores -n */
12650 }
12651 flag_off = ~flag_off;
12652
12653 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12654 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012655 aptr = argptr;
12656 name = *aptr;
12657 if (name) {
12658 do {
12659 p = strchr(name, '=');
12660 if (p != NULL) {
12661 p++;
12662 } else {
12663 vp = *findvar(hashvar(name), name);
12664 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012665 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012666 continue;
12667 }
Eric Andersencb57d552001-06-28 07:25:16 +000012668 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012669 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012670 } while ((name = *++aptr) != NULL);
12671 return 0;
12672 }
Eric Andersencb57d552001-06-28 07:25:16 +000012673 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012674
12675 /* No arguments. Show the list of exported or readonly vars.
12676 * -n is ignored.
12677 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012678 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012679 return 0;
12680}
12681
Eric Andersencb57d552001-06-28 07:25:16 +000012682/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012683 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012684 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012685static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012686unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012687{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012688 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012689
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012690 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012691 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012692 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012693}
12694
Eric Andersencb57d552001-06-28 07:25:16 +000012695/*
Eric Andersencb57d552001-06-28 07:25:16 +000012696 * The unset builtin command. We unset the function before we unset the
12697 * variable to allow a function to be unset when there is a readonly variable
12698 * with the same name.
12699 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012700static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012701unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012702{
12703 char **ap;
12704 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012705 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012706 int ret = 0;
12707
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012708 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012709 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012710 }
Eric Andersencb57d552001-06-28 07:25:16 +000012711
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012712 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012713 if (flag != 'f') {
12714 i = unsetvar(*ap);
12715 ret |= i;
12716 if (!(i & 2))
12717 continue;
12718 }
12719 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012720 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012721 }
Eric Andersenc470f442003-07-28 09:56:35 +000012722 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012723}
12724
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012725static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012726 ' ', offsetof(struct tms, tms_utime),
12727 '\n', offsetof(struct tms, tms_stime),
12728 ' ', offsetof(struct tms, tms_cutime),
12729 '\n', offsetof(struct tms, tms_cstime),
12730 0
12731};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012732static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012733timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012734{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012735 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012736 const unsigned char *p;
12737 struct tms buf;
12738
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012739 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012740 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012741
12742 p = timescmd_str;
12743 do {
12744 t = *(clock_t *)(((char *) &buf) + p[1]);
12745 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012746 t = t % clk_tck;
12747 out1fmt("%lum%lu.%03lus%c",
12748 s / 60, s % 60,
12749 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012750 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012751 p += 2;
12752 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012753
Eric Andersencb57d552001-06-28 07:25:16 +000012754 return 0;
12755}
12756
Mike Frysinger98c52642009-04-02 10:02:37 +000012757#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012758/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012759 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012760 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012761 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012762 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012763 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012764static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012765letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012766{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012767 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012768
Denis Vlasenko68404f12008-03-17 09:00:54 +000012769 argv++;
12770 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012771 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012772 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012773 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012774 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012775
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012776 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012777}
Eric Andersenc470f442003-07-28 09:56:35 +000012778#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012779
Eric Andersenc470f442003-07-28 09:56:35 +000012780/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012781 * The read builtin. Options:
12782 * -r Do not interpret '\' specially
12783 * -s Turn off echo (tty only)
12784 * -n NCHARS Read NCHARS max
12785 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12786 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12787 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012788 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012789 * TODO: bash also has:
12790 * -a ARRAY Read into array[0],[1],etc
12791 * -d DELIM End on DELIM char, not newline
12792 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012793 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012794static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012795readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012796{
Denys Vlasenko73067272010-01-12 22:11:24 +010012797 char *opt_n = NULL;
12798 char *opt_p = NULL;
12799 char *opt_t = NULL;
12800 char *opt_u = NULL;
12801 int read_flags = 0;
12802 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012803 int i;
12804
Denys Vlasenko73067272010-01-12 22:11:24 +010012805 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012806 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012807 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012808 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012809 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012810 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012811 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012812 break;
12813 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012814 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012815 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012816 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012817 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012818 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012819 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012820 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012821 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012822 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012823 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012824 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012825 default:
12826 break;
12827 }
Eric Andersenc470f442003-07-28 09:56:35 +000012828 }
Paul Fox02eb9342005-09-07 16:56:02 +000012829
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012830 /* "read -s" needs to save/restore termios, can't allow ^C
12831 * to jump out of it.
12832 */
12833 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012834 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010012835 argptr,
12836 bltinlookup("IFS"), /* can be NULL */
12837 read_flags,
12838 opt_n,
12839 opt_p,
12840 opt_t,
12841 opt_u
12842 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012843 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012844
Denys Vlasenko73067272010-01-12 22:11:24 +010012845 if ((uintptr_t)r > 1)
12846 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012847
Denys Vlasenko73067272010-01-12 22:11:24 +010012848 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012849}
12850
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012851static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012852umaskcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012853{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012854 static const char permuser[3] ALIGN1 = "ugo";
12855 static const char permmode[3] ALIGN1 = "rwx";
12856 static const short permmask[] ALIGN2 = {
Eric Andersenc470f442003-07-28 09:56:35 +000012857 S_IRUSR, S_IWUSR, S_IXUSR,
12858 S_IRGRP, S_IWGRP, S_IXGRP,
12859 S_IROTH, S_IWOTH, S_IXOTH
12860 };
12861
Denis Vlasenkoeb858492009-04-18 02:06:54 +000012862 /* TODO: use bb_parse_mode() instead */
12863
Eric Andersenc470f442003-07-28 09:56:35 +000012864 char *ap;
12865 mode_t mask;
12866 int i;
12867 int symbolic_mode = 0;
12868
12869 while (nextopt("S") != '\0') {
12870 symbolic_mode = 1;
12871 }
12872
Denis Vlasenkob012b102007-02-19 22:43:01 +000012873 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012874 mask = umask(0);
12875 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012876 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000012877
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012878 ap = *argptr;
12879 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012880 if (symbolic_mode) {
12881 char buf[18];
12882 char *p = buf;
12883
12884 for (i = 0; i < 3; i++) {
12885 int j;
12886
12887 *p++ = permuser[i];
12888 *p++ = '=';
12889 for (j = 0; j < 3; j++) {
12890 if ((mask & permmask[3 * i + j]) == 0) {
12891 *p++ = permmode[j];
12892 }
12893 }
12894 *p++ = ',';
12895 }
12896 *--p = 0;
12897 puts(buf);
12898 } else {
12899 out1fmt("%.4o\n", mask);
12900 }
12901 } else {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012902 if (isdigit((unsigned char) *ap)) {
Eric Andersenc470f442003-07-28 09:56:35 +000012903 mask = 0;
12904 do {
12905 if (*ap >= '8' || *ap < '0')
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020012906 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012907 mask = (mask << 3) + (*ap - '0');
12908 } while (*++ap != '\0');
12909 umask(mask);
12910 } else {
12911 mask = ~mask & 0777;
12912 if (!bb_parse_mode(ap, &mask)) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000012913 ash_msg_and_raise_error("illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012914 }
12915 umask(~mask & 0777);
12916 }
12917 }
12918 return 0;
12919}
12920
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012921static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012922ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012923{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012924 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012925}
12926
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012927/* ============ main() and helpers */
12928
12929/*
12930 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012931 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012932static void
12933exitshell(void)
12934{
12935 struct jmploc loc;
12936 char *p;
12937 int status;
12938
Denys Vlasenkobede2152011-09-04 16:12:33 +020012939#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
12940 save_history(line_input_state);
12941#endif
12942
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012943 status = exitstatus;
12944 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12945 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000012946 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012947/* dash bug: it just does _exit(exitstatus) here
12948 * but we have to do setjobctl(0) first!
12949 * (bug is still not fixed in dash-0.5.3 - if you run dash
12950 * under Midnight Commander, on exit from dash MC is backgrounded) */
12951 status = exitstatus;
12952 goto out;
12953 }
12954 exception_handler = &loc;
12955 p = trap[0];
12956 if (p) {
12957 trap[0] = NULL;
12958 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020012959 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012960 }
12961 flush_stdout_stderr();
12962 out:
12963 setjobctl(0);
12964 _exit(status);
12965 /* NOTREACHED */
12966}
12967
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012968static void
12969init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012970{
12971 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020012972 /* we will never free this */
12973 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012974
12975 /* from trap.c: */
12976 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010012977 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12978 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12979 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020012980 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012981
12982 /* from var.c: */
12983 {
12984 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012985 const char *p;
12986 struct stat st1, st2;
12987
12988 initvar();
12989 for (envp = environ; envp && *envp; envp++) {
12990 if (strchr(*envp, '=')) {
12991 setvareq(*envp, VEXPORT|VTEXTFIXED);
12992 }
12993 }
12994
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012995 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010012996#if ENABLE_ASH_BASH_COMPAT
12997 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010012998 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020012999 if (!lookupvar("HOSTNAME")) {
13000 struct utsname uts;
13001 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013002 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013003 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013004#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013005 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013006 if (p) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013007 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013008 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13009 ) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013010 p = '\0';
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013011 }
13012 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013013 setpwd(p, 0);
13014 }
13015}
13016
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013017
13018//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013019//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013020//usage:#define ash_full_usage "\n\n"
13021//usage: "Unix shell interpreter"
13022
13023//usage:#if ENABLE_FEATURE_SH_IS_ASH
13024//usage:# define sh_trivial_usage ash_trivial_usage
13025//usage:# define sh_full_usage ash_full_usage
13026//usage:#endif
13027//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13028//usage:# define bash_trivial_usage ash_trivial_usage
13029//usage:# define bash_full_usage ash_full_usage
13030//usage:#endif
13031
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013032/*
13033 * Process the shell command line arguments.
13034 */
13035static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013036procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013037{
13038 int i;
13039 const char *xminusc;
13040 char **xargv;
13041
13042 xargv = argv;
13043 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013044 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013045 xargv++;
13046 for (i = 0; i < NOPTS; i++)
13047 optlist[i] = 2;
13048 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013049 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013050 /* it already printed err message */
13051 raise_exception(EXERROR);
13052 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013053 xargv = argptr;
13054 xminusc = minusc;
13055 if (*xargv == NULL) {
13056 if (xminusc)
13057 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13058 sflag = 1;
13059 }
13060 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13061 iflag = 1;
13062 if (mflag == 2)
13063 mflag = iflag;
13064 for (i = 0; i < NOPTS; i++)
13065 if (optlist[i] == 2)
13066 optlist[i] = 0;
13067#if DEBUG == 2
13068 debug = 1;
13069#endif
13070 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13071 if (xminusc) {
13072 minusc = *xargv++;
13073 if (*xargv)
13074 goto setarg0;
13075 } else if (!sflag) {
13076 setinputfile(*xargv, 0);
13077 setarg0:
13078 arg0 = *xargv++;
13079 commandname = arg0;
13080 }
13081
13082 shellparam.p = xargv;
13083#if ENABLE_ASH_GETOPTS
13084 shellparam.optind = 1;
13085 shellparam.optoff = -1;
13086#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013087 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013088 while (*xargv) {
13089 shellparam.nparam++;
13090 xargv++;
13091 }
13092 optschanged();
13093}
13094
13095/*
13096 * Read /etc/profile or .profile.
13097 */
13098static void
13099read_profile(const char *name)
13100{
13101 int skip;
13102
13103 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13104 return;
13105 skip = cmdloop(0);
13106 popfile();
13107 if (skip)
13108 exitshell();
13109}
13110
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013111/*
13112 * This routine is called when an error or an interrupt occurs in an
13113 * interactive shell and control is returned to the main command loop.
13114 */
13115static void
13116reset(void)
13117{
13118 /* from eval.c: */
13119 evalskip = 0;
13120 loopnest = 0;
13121 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013122 g_parsefile->left_in_buffer = 0;
13123 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013124 popallfiles();
13125 /* from parser.c: */
13126 tokpushback = 0;
13127 checkkwd = 0;
13128 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013129 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013130}
13131
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013132#if PROFILE
13133static short profile_buf[16384];
13134extern int etext();
13135#endif
13136
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013137/*
13138 * Main routine. We initialize things, parse the arguments, execute
13139 * profiles if we're a login shell, and then call cmdloop to execute
13140 * commands. The setjmp call sets up the location to jump to when an
13141 * exception occurs. When an exception occurs the variable "state"
13142 * is used to figure out how far we had gotten.
13143 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013144int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013145int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013146{
Mike Frysinger98c52642009-04-02 10:02:37 +000013147 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013148 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013149 struct jmploc jmploc;
13150 struct stackmark smark;
13151
Denis Vlasenko01631112007-12-16 17:20:38 +000013152 /* Initialize global data */
13153 INIT_G_misc();
13154 INIT_G_memstack();
13155 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013156#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013157 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013158#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013159 INIT_G_cmdtable();
13160
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013161#if PROFILE
13162 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13163#endif
13164
13165#if ENABLE_FEATURE_EDITING
13166 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13167#endif
13168 state = 0;
13169 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013170 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013171 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013172
13173 reset();
13174
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013175 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013176 if (e == EXERROR)
13177 exitstatus = 2;
13178 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013179 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013180 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013181 }
13182 if (e == EXINT) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013183 outcslow('\n', stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013184 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013185
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013186 popstackmark(&smark);
13187 FORCE_INT_ON; /* enable interrupts */
13188 if (s == 1)
13189 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013190 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013191 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013192 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013193 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013194 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013195 }
13196 exception_handler = &jmploc;
13197#if DEBUG
13198 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013199 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013200 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013201#endif
13202 rootpid = getpid();
13203
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013204 init();
13205 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013206 procargs(argv);
13207
Denys Vlasenko6088e132010-12-25 23:58:42 +010013208 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013209 isloginsh = 1;
13210 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013211 const char *hp;
13212
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013213 state = 1;
13214 read_profile("/etc/profile");
13215 state1:
13216 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013217 hp = lookupvar("HOME");
13218 if (hp) {
13219 hp = concat_path_file(hp, ".profile");
13220 read_profile(hp);
13221 free((char*)hp);
13222 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013223 }
13224 state2:
13225 state = 3;
13226 if (
13227#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013228 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013229#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013230 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013231 ) {
13232 shinit = lookupvar("ENV");
13233 if (shinit != NULL && *shinit != '\0') {
13234 read_profile(shinit);
13235 }
13236 }
13237 state3:
13238 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013239 if (minusc) {
13240 /* evalstring pushes parsefile stack.
13241 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013242 * is one of stacked source fds.
13243 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013244 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013245 // ^^ not necessary since now we special-case fd 0
13246 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013247 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013248 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013249
13250 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013251#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013252 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013253 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013254 if (!hp) {
13255 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013256 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013257 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013258 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013259 free((char*)hp);
13260 hp = lookupvar("HISTFILE");
13261 }
13262 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013263 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013264 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013265# if ENABLE_FEATURE_SH_HISTFILESIZE
13266 hp = lookupvar("HISTFILESIZE");
13267 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13268# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013269 }
13270#endif
13271 state4: /* XXX ??? - why isn't this before the "if" statement */
13272 cmdloop(1);
13273 }
13274#if PROFILE
13275 monitor(0);
13276#endif
13277#ifdef GPROF
13278 {
13279 extern void _mcleanup(void);
13280 _mcleanup();
13281 }
13282#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013283 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013284 exitshell();
13285 /* NOTREACHED */
13286}
13287
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013288
Eric Andersendf82f612001-06-28 07:46:40 +000013289/*-
13290 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013291 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013292 *
13293 * This code is derived from software contributed to Berkeley by
13294 * Kenneth Almquist.
13295 *
13296 * Redistribution and use in source and binary forms, with or without
13297 * modification, are permitted provided that the following conditions
13298 * are met:
13299 * 1. Redistributions of source code must retain the above copyright
13300 * notice, this list of conditions and the following disclaimer.
13301 * 2. Redistributions in binary form must reproduce the above copyright
13302 * notice, this list of conditions and the following disclaimer in the
13303 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013304 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013305 * may be used to endorse or promote products derived from this software
13306 * without specific prior written permission.
13307 *
13308 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13309 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13310 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13311 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13312 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13313 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13314 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13315 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13316 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13317 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13318 * SUCH DAMAGE.
13319 */