blob: 697a64feaf22817610f4d4915c12904b11cc95cd [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')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000601#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
602/* CTLBACKQ | CTLQUOTE == '\205' */
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200603#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
604#define CTLENDARI ((unsigned char)'\207')
605#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100606#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000607
608/* variable substitution byte (follows CTLVAR) */
609#define VSTYPE 0x0f /* type of variable substitution */
610#define VSNUL 0x10 /* colon--treat the empty string as unset */
611#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
612
613/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000614#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
615#define VSMINUS 0x2 /* ${var-text} */
616#define VSPLUS 0x3 /* ${var+text} */
617#define VSQUESTION 0x4 /* ${var?message} */
618#define VSASSIGN 0x5 /* ${var=text} */
619#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
620#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
621#define VSTRIMLEFT 0x8 /* ${var#pattern} */
622#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
623#define VSLENGTH 0xa /* ${#var} */
624#if ENABLE_ASH_BASH_COMPAT
625#define VSSUBSTR 0xc /* ${var:position:length} */
626#define VSREPLACE 0xd /* ${var/pattern/replacement} */
627#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
628#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000629
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000630static const char dolatstr[] ALIGN1 = {
631 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
632};
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000633
Denis Vlasenko559691a2008-10-05 18:39:31 +0000634#define NCMD 0
635#define NPIPE 1
636#define NREDIR 2
637#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000638#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000639#define NAND 5
640#define NOR 6
641#define NSEMI 7
642#define NIF 8
643#define NWHILE 9
644#define NUNTIL 10
645#define NFOR 11
646#define NCASE 12
647#define NCLIST 13
648#define NDEFUN 14
649#define NARG 15
650#define NTO 16
651#if ENABLE_ASH_BASH_COMPAT
652#define NTO2 17
653#endif
654#define NCLOBBER 18
655#define NFROM 19
656#define NFROMTO 20
657#define NAPPEND 21
658#define NTOFD 22
659#define NFROMFD 23
660#define NHERE 24
661#define NXHERE 25
662#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000663#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000664
665union node;
666
667struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000668 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000669 union node *assign;
670 union node *args;
671 union node *redirect;
672};
673
674struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000675 smallint type;
676 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000677 struct nodelist *cmdlist;
678};
679
680struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000681 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000682 union node *n;
683 union node *redirect;
684};
685
686struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000687 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000688 union node *ch1;
689 union node *ch2;
690};
691
692struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000693 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000694 union node *test;
695 union node *ifpart;
696 union node *elsepart;
697};
698
699struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000700 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000701 union node *args;
702 union node *body;
703 char *var;
704};
705
706struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000707 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000708 union node *expr;
709 union node *cases;
710};
711
712struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000713 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000714 union node *next;
715 union node *pattern;
716 union node *body;
717};
718
719struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000720 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000721 union node *next;
722 char *text;
723 struct nodelist *backquote;
724};
725
Denis Vlasenko559691a2008-10-05 18:39:31 +0000726/* nfile and ndup layout must match!
727 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
728 * that it is actually NTO2 (>&file), and change its type.
729 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000730struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000731 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000732 union node *next;
733 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000734 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000735 union node *fname;
736 char *expfname;
737};
738
739struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000740 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000741 union node *next;
742 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000743 int dupfd;
744 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000745 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000746};
747
748struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000749 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000750 union node *next;
751 int fd;
752 union node *doc;
753};
754
755struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000756 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000757 union node *com;
758};
759
760union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000761 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000762 struct ncmd ncmd;
763 struct npipe npipe;
764 struct nredir nredir;
765 struct nbinary nbinary;
766 struct nif nif;
767 struct nfor nfor;
768 struct ncase ncase;
769 struct nclist nclist;
770 struct narg narg;
771 struct nfile nfile;
772 struct ndup ndup;
773 struct nhere nhere;
774 struct nnot nnot;
775};
776
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200777/*
778 * NODE_EOF is returned by parsecmd when it encounters an end of file.
779 * It must be distinct from NULL.
780 */
781#define NODE_EOF ((union node *) -1L)
782
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000783struct nodelist {
784 struct nodelist *next;
785 union node *n;
786};
787
788struct funcnode {
789 int count;
790 union node n;
791};
792
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000793/*
794 * Free a parse tree.
795 */
796static void
797freefunc(struct funcnode *f)
798{
799 if (f && --f->count < 0)
800 free(f);
801}
802
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000803
804/* ============ Debugging output */
805
806#if DEBUG
807
808static FILE *tracefile;
809
810static void
811trace_printf(const char *fmt, ...)
812{
813 va_list va;
814
815 if (debug != 1)
816 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000817 if (DEBUG_TIME)
818 fprintf(tracefile, "%u ", (int) time(NULL));
819 if (DEBUG_PID)
820 fprintf(tracefile, "[%u] ", (int) getpid());
821 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200822 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000823 va_start(va, fmt);
824 vfprintf(tracefile, fmt, va);
825 va_end(va);
826}
827
828static void
829trace_vprintf(const char *fmt, va_list va)
830{
831 if (debug != 1)
832 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000833 if (DEBUG_TIME)
834 fprintf(tracefile, "%u ", (int) time(NULL));
835 if (DEBUG_PID)
836 fprintf(tracefile, "[%u] ", (int) getpid());
837 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200838 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000839 vfprintf(tracefile, fmt, va);
840}
841
842static void
843trace_puts(const char *s)
844{
845 if (debug != 1)
846 return;
847 fputs(s, tracefile);
848}
849
850static void
851trace_puts_quoted(char *s)
852{
853 char *p;
854 char c;
855
856 if (debug != 1)
857 return;
858 putc('"', tracefile);
859 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100860 switch ((unsigned char)*p) {
861 case '\n': c = 'n'; goto backslash;
862 case '\t': c = 't'; goto backslash;
863 case '\r': c = 'r'; goto backslash;
864 case '\"': c = '\"'; goto backslash;
865 case '\\': c = '\\'; goto backslash;
866 case CTLESC: c = 'e'; goto backslash;
867 case CTLVAR: c = 'v'; goto backslash;
868 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
869 case CTLBACKQ: c = 'q'; goto backslash;
870 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000871 backslash:
872 putc('\\', tracefile);
873 putc(c, tracefile);
874 break;
875 default:
876 if (*p >= ' ' && *p <= '~')
877 putc(*p, tracefile);
878 else {
879 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100880 putc((*p >> 6) & 03, tracefile);
881 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000882 putc(*p & 07, tracefile);
883 }
884 break;
885 }
886 }
887 putc('"', tracefile);
888}
889
890static void
891trace_puts_args(char **ap)
892{
893 if (debug != 1)
894 return;
895 if (!*ap)
896 return;
897 while (1) {
898 trace_puts_quoted(*ap);
899 if (!*++ap) {
900 putc('\n', tracefile);
901 break;
902 }
903 putc(' ', tracefile);
904 }
905}
906
907static void
908opentrace(void)
909{
910 char s[100];
911#ifdef O_APPEND
912 int flags;
913#endif
914
915 if (debug != 1) {
916 if (tracefile)
917 fflush(tracefile);
918 /* leave open because libedit might be using it */
919 return;
920 }
921 strcpy(s, "./trace");
922 if (tracefile) {
923 if (!freopen(s, "a", tracefile)) {
924 fprintf(stderr, "Can't re-open %s\n", s);
925 debug = 0;
926 return;
927 }
928 } else {
929 tracefile = fopen(s, "a");
930 if (tracefile == NULL) {
931 fprintf(stderr, "Can't open %s\n", s);
932 debug = 0;
933 return;
934 }
935 }
936#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000937 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000938 if (flags >= 0)
939 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
940#endif
941 setlinebuf(tracefile);
942 fputs("\nTracing started.\n", tracefile);
943}
944
945static void
946indent(int amount, char *pfx, FILE *fp)
947{
948 int i;
949
950 for (i = 0; i < amount; i++) {
951 if (pfx && i == amount - 1)
952 fputs(pfx, fp);
953 putc('\t', fp);
954 }
955}
956
957/* little circular references here... */
958static void shtree(union node *n, int ind, char *pfx, FILE *fp);
959
960static void
961sharg(union node *arg, FILE *fp)
962{
963 char *p;
964 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100965 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000966
967 if (arg->type != NARG) {
968 out1fmt("<node type %d>\n", arg->type);
969 abort();
970 }
971 bqlist = arg->narg.backquote;
972 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100973 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000974 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700975 p++;
976 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000977 break;
978 case CTLVAR:
979 putc('$', fp);
980 putc('{', fp);
981 subtype = *++p;
982 if (subtype == VSLENGTH)
983 putc('#', fp);
984
Dan Fandrich77d48722010-09-07 23:38:28 -0700985 while (*p != '=') {
986 putc(*p, fp);
987 p++;
988 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000989
990 if (subtype & VSNUL)
991 putc(':', fp);
992
993 switch (subtype & VSTYPE) {
994 case VSNORMAL:
995 putc('}', fp);
996 break;
997 case VSMINUS:
998 putc('-', fp);
999 break;
1000 case VSPLUS:
1001 putc('+', fp);
1002 break;
1003 case VSQUESTION:
1004 putc('?', fp);
1005 break;
1006 case VSASSIGN:
1007 putc('=', fp);
1008 break;
1009 case VSTRIMLEFT:
1010 putc('#', fp);
1011 break;
1012 case VSTRIMLEFTMAX:
1013 putc('#', fp);
1014 putc('#', fp);
1015 break;
1016 case VSTRIMRIGHT:
1017 putc('%', fp);
1018 break;
1019 case VSTRIMRIGHTMAX:
1020 putc('%', fp);
1021 putc('%', fp);
1022 break;
1023 case VSLENGTH:
1024 break;
1025 default:
1026 out1fmt("<subtype %d>", subtype);
1027 }
1028 break;
1029 case CTLENDVAR:
1030 putc('}', fp);
1031 break;
1032 case CTLBACKQ:
1033 case CTLBACKQ|CTLQUOTE:
1034 putc('$', fp);
1035 putc('(', fp);
1036 shtree(bqlist->n, -1, NULL, fp);
1037 putc(')', fp);
1038 break;
1039 default:
1040 putc(*p, fp);
1041 break;
1042 }
1043 }
1044}
1045
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001046static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001047shcmd(union node *cmd, FILE *fp)
1048{
1049 union node *np;
1050 int first;
1051 const char *s;
1052 int dftfd;
1053
1054 first = 1;
1055 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001056 if (!first)
1057 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001058 sharg(np, fp);
1059 first = 0;
1060 }
1061 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001062 if (!first)
1063 putc(' ', fp);
1064 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001065 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001066 case NTO: s = ">>"+1; dftfd = 1; break;
1067 case NCLOBBER: s = ">|"; dftfd = 1; break;
1068 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001069#if ENABLE_ASH_BASH_COMPAT
1070 case NTO2:
1071#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001072 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001073 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001074 case NFROMFD: s = "<&"; break;
1075 case NFROMTO: s = "<>"; break;
1076 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001077 }
1078 if (np->nfile.fd != dftfd)
1079 fprintf(fp, "%d", np->nfile.fd);
1080 fputs(s, fp);
1081 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1082 fprintf(fp, "%d", np->ndup.dupfd);
1083 } else {
1084 sharg(np->nfile.fname, fp);
1085 }
1086 first = 0;
1087 }
1088}
1089
1090static void
1091shtree(union node *n, int ind, char *pfx, FILE *fp)
1092{
1093 struct nodelist *lp;
1094 const char *s;
1095
1096 if (n == NULL)
1097 return;
1098
1099 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001100
1101 if (n == NODE_EOF) {
1102 fputs("<EOF>", fp);
1103 return;
1104 }
1105
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001106 switch (n->type) {
1107 case NSEMI:
1108 s = "; ";
1109 goto binop;
1110 case NAND:
1111 s = " && ";
1112 goto binop;
1113 case NOR:
1114 s = " || ";
1115 binop:
1116 shtree(n->nbinary.ch1, ind, NULL, fp);
1117 /* if (ind < 0) */
1118 fputs(s, fp);
1119 shtree(n->nbinary.ch2, ind, NULL, fp);
1120 break;
1121 case NCMD:
1122 shcmd(n, fp);
1123 if (ind >= 0)
1124 putc('\n', fp);
1125 break;
1126 case NPIPE:
1127 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001128 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001129 if (lp->next)
1130 fputs(" | ", fp);
1131 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001132 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001133 fputs(" &", fp);
1134 if (ind >= 0)
1135 putc('\n', fp);
1136 break;
1137 default:
1138 fprintf(fp, "<node type %d>", n->type);
1139 if (ind >= 0)
1140 putc('\n', fp);
1141 break;
1142 }
1143}
1144
1145static void
1146showtree(union node *n)
1147{
1148 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001149 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001150}
1151
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001152#endif /* DEBUG */
1153
1154
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001155/* ============ Parser data */
1156
1157/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001158 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1159 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001160struct strlist {
1161 struct strlist *next;
1162 char *text;
1163};
1164
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001165struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001166
Denis Vlasenkob012b102007-02-19 22:43:01 +00001167struct strpush {
1168 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001169 char *prev_string;
1170 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001171#if ENABLE_ASH_ALIAS
1172 struct alias *ap; /* if push was associated with an alias */
1173#endif
1174 char *string; /* remember the string since it may change */
1175};
1176
1177struct parsefile {
1178 struct parsefile *prev; /* preceding file on stack */
1179 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001180 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001181 int left_in_line; /* number of chars left in this line */
1182 int left_in_buffer; /* number of chars left in this buffer past the line */
1183 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001184 char *buf; /* input buffer */
1185 struct strpush *strpush; /* for pushing strings at this level */
1186 struct strpush basestrpush; /* so pushing one is fast */
1187};
1188
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001189static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001190static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001191static int startlinno; /* line # where last token started */
1192static char *commandname; /* currently executing command */
1193static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001194static uint8_t exitstatus; /* exit status of last command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001195
1196
1197/* ============ Message printing */
1198
1199static void
1200ash_vmsg(const char *msg, va_list ap)
1201{
1202 fprintf(stderr, "%s: ", arg0);
1203 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001204 if (strcmp(arg0, commandname))
1205 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001206 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001207 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001208 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001209 vfprintf(stderr, msg, ap);
1210 outcslow('\n', stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001211}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001212
1213/*
1214 * Exverror is called to raise the error exception. If the second argument
1215 * is not NULL then error prints an error message using printf style
1216 * formatting. It then raises the error exception.
1217 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001218static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001219static void
1220ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001221{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001222#if DEBUG
1223 if (msg) {
1224 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1225 TRACEV((msg, ap));
1226 TRACE(("\") pid=%d\n", getpid()));
1227 } else
1228 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1229 if (msg)
1230#endif
1231 ash_vmsg(msg, ap);
1232
1233 flush_stdout_stderr();
1234 raise_exception(cond);
1235 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001236}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001237
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001238static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001239static void
1240ash_msg_and_raise_error(const char *msg, ...)
1241{
1242 va_list ap;
1243
1244 va_start(ap, msg);
1245 ash_vmsg_and_raise(EXERROR, msg, ap);
1246 /* NOTREACHED */
1247 va_end(ap);
1248}
1249
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001250static void raise_error_syntax(const char *) NORETURN;
1251static void
1252raise_error_syntax(const char *msg)
1253{
1254 ash_msg_and_raise_error("syntax error: %s", msg);
1255 /* NOTREACHED */
1256}
1257
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001258static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001259static void
1260ash_msg_and_raise(int cond, const char *msg, ...)
1261{
1262 va_list ap;
1263
1264 va_start(ap, msg);
1265 ash_vmsg_and_raise(cond, msg, ap);
1266 /* NOTREACHED */
1267 va_end(ap);
1268}
1269
1270/*
1271 * error/warning routines for external builtins
1272 */
1273static void
1274ash_msg(const char *fmt, ...)
1275{
1276 va_list ap;
1277
1278 va_start(ap, fmt);
1279 ash_vmsg(fmt, ap);
1280 va_end(ap);
1281}
1282
1283/*
1284 * Return a string describing an error. The returned string may be a
1285 * pointer to a static buffer that will be overwritten on the next call.
1286 * Action describes the operation that got the error.
1287 */
1288static const char *
1289errmsg(int e, const char *em)
1290{
1291 if (e == ENOENT || e == ENOTDIR) {
1292 return em;
1293 }
1294 return strerror(e);
1295}
1296
1297
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001298/* ============ Memory allocation */
1299
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001300#if 0
1301/* I consider these wrappers nearly useless:
1302 * ok, they return you to nearest exception handler, but
1303 * how much memory do you leak in the process, making
1304 * memory starvation worse?
1305 */
1306static void *
1307ckrealloc(void * p, size_t nbytes)
1308{
1309 p = realloc(p, nbytes);
1310 if (!p)
1311 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1312 return p;
1313}
1314
1315static void *
1316ckmalloc(size_t nbytes)
1317{
1318 return ckrealloc(NULL, nbytes);
1319}
1320
1321static void *
1322ckzalloc(size_t nbytes)
1323{
1324 return memset(ckmalloc(nbytes), 0, nbytes);
1325}
1326
1327static char *
1328ckstrdup(const char *s)
1329{
1330 char *p = strdup(s);
1331 if (!p)
1332 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1333 return p;
1334}
1335#else
1336/* Using bbox equivalents. They exit if out of memory */
1337# define ckrealloc xrealloc
1338# define ckmalloc xmalloc
1339# define ckzalloc xzalloc
1340# define ckstrdup xstrdup
1341#endif
1342
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001343/*
1344 * It appears that grabstackstr() will barf with such alignments
1345 * because stalloc() will return a string allocated in a new stackblock.
1346 */
1347#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1348enum {
1349 /* Most machines require the value returned from malloc to be aligned
1350 * in some way. The following macro will get this right
1351 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001352 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001353 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001354 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001355};
1356
1357struct stack_block {
1358 struct stack_block *prev;
1359 char space[MINSIZE];
1360};
1361
1362struct stackmark {
1363 struct stack_block *stackp;
1364 char *stacknxt;
1365 size_t stacknleft;
1366 struct stackmark *marknext;
1367};
1368
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001369
Denis Vlasenko01631112007-12-16 17:20:38 +00001370struct globals_memstack {
1371 struct stack_block *g_stackp; // = &stackbase;
1372 struct stackmark *markp;
1373 char *g_stacknxt; // = stackbase.space;
1374 char *sstrend; // = stackbase.space + MINSIZE;
1375 size_t g_stacknleft; // = MINSIZE;
1376 int herefd; // = -1;
1377 struct stack_block stackbase;
1378};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001379extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1380#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001381#define g_stackp (G_memstack.g_stackp )
1382#define markp (G_memstack.markp )
1383#define g_stacknxt (G_memstack.g_stacknxt )
1384#define sstrend (G_memstack.sstrend )
1385#define g_stacknleft (G_memstack.g_stacknleft)
1386#define herefd (G_memstack.herefd )
1387#define stackbase (G_memstack.stackbase )
1388#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001389 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1390 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001391 g_stackp = &stackbase; \
1392 g_stacknxt = stackbase.space; \
1393 g_stacknleft = MINSIZE; \
1394 sstrend = stackbase.space + MINSIZE; \
1395 herefd = -1; \
1396} while (0)
1397
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001398
Denis Vlasenko01631112007-12-16 17:20:38 +00001399#define stackblock() ((void *)g_stacknxt)
1400#define stackblocksize() g_stacknleft
1401
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001402/*
1403 * Parse trees for commands are allocated in lifo order, so we use a stack
1404 * to make this more efficient, and also to avoid all sorts of exception
1405 * handling code to handle interrupts in the middle of a parse.
1406 *
1407 * The size 504 was chosen because the Ultrix malloc handles that size
1408 * well.
1409 */
1410static void *
1411stalloc(size_t nbytes)
1412{
1413 char *p;
1414 size_t aligned;
1415
1416 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001417 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001418 size_t len;
1419 size_t blocksize;
1420 struct stack_block *sp;
1421
1422 blocksize = aligned;
1423 if (blocksize < MINSIZE)
1424 blocksize = MINSIZE;
1425 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1426 if (len < blocksize)
1427 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1428 INT_OFF;
1429 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001430 sp->prev = g_stackp;
1431 g_stacknxt = sp->space;
1432 g_stacknleft = blocksize;
1433 sstrend = g_stacknxt + blocksize;
1434 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001435 INT_ON;
1436 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001437 p = g_stacknxt;
1438 g_stacknxt += aligned;
1439 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001440 return p;
1441}
1442
Denis Vlasenko597906c2008-02-20 16:38:54 +00001443static void *
1444stzalloc(size_t nbytes)
1445{
1446 return memset(stalloc(nbytes), 0, nbytes);
1447}
1448
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001449static void
1450stunalloc(void *p)
1451{
1452#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001453 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001454 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001455 abort();
1456 }
1457#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001458 g_stacknleft += g_stacknxt - (char *)p;
1459 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001460}
1461
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001462/*
1463 * Like strdup but works with the ash stack.
1464 */
1465static char *
1466ststrdup(const char *p)
1467{
1468 size_t len = strlen(p) + 1;
1469 return memcpy(stalloc(len), p, len);
1470}
1471
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001472static void
1473setstackmark(struct stackmark *mark)
1474{
Denis Vlasenko01631112007-12-16 17:20:38 +00001475 mark->stackp = g_stackp;
1476 mark->stacknxt = g_stacknxt;
1477 mark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001478 mark->marknext = markp;
1479 markp = mark;
1480}
1481
1482static void
1483popstackmark(struct stackmark *mark)
1484{
1485 struct stack_block *sp;
1486
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001487 if (!mark->stackp)
1488 return;
1489
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001490 INT_OFF;
1491 markp = mark->marknext;
Denis Vlasenko01631112007-12-16 17:20:38 +00001492 while (g_stackp != mark->stackp) {
1493 sp = g_stackp;
1494 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001495 free(sp);
1496 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001497 g_stacknxt = mark->stacknxt;
1498 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001499 sstrend = mark->stacknxt + mark->stacknleft;
1500 INT_ON;
1501}
1502
1503/*
1504 * When the parser reads in a string, it wants to stick the string on the
1505 * stack and only adjust the stack pointer when it knows how big the
1506 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1507 * of space on top of the stack and stackblocklen returns the length of
1508 * this block. Growstackblock will grow this space by at least one byte,
1509 * possibly moving it (like realloc). Grabstackblock actually allocates the
1510 * part of the block that has been used.
1511 */
1512static void
1513growstackblock(void)
1514{
1515 size_t newlen;
1516
Denis Vlasenko01631112007-12-16 17:20:38 +00001517 newlen = g_stacknleft * 2;
1518 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001519 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1520 if (newlen < 128)
1521 newlen += 128;
1522
Denis Vlasenko01631112007-12-16 17:20:38 +00001523 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001524 struct stack_block *oldstackp;
1525 struct stackmark *xmark;
1526 struct stack_block *sp;
1527 struct stack_block *prevstackp;
1528 size_t grosslen;
1529
1530 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001531 oldstackp = g_stackp;
1532 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001533 prevstackp = sp->prev;
1534 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1535 sp = ckrealloc(sp, grosslen);
1536 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001537 g_stackp = sp;
1538 g_stacknxt = sp->space;
1539 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001540 sstrend = sp->space + newlen;
1541
1542 /*
1543 * Stack marks pointing to the start of the old block
1544 * must be relocated to point to the new block
1545 */
1546 xmark = markp;
1547 while (xmark != NULL && xmark->stackp == oldstackp) {
Denis Vlasenko01631112007-12-16 17:20:38 +00001548 xmark->stackp = g_stackp;
1549 xmark->stacknxt = g_stacknxt;
1550 xmark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001551 xmark = xmark->marknext;
1552 }
1553 INT_ON;
1554 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001555 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001556 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001557 char *p = stalloc(newlen);
1558
1559 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001560 g_stacknxt = memcpy(p, oldspace, oldlen);
1561 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001562 }
1563}
1564
1565static void
1566grabstackblock(size_t len)
1567{
1568 len = SHELL_ALIGN(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001569 g_stacknxt += len;
1570 g_stacknleft -= len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001571}
1572
1573/*
1574 * The following routines are somewhat easier to use than the above.
1575 * The user declares a variable of type STACKSTR, which may be declared
1576 * to be a register. The macro STARTSTACKSTR initializes things. Then
1577 * the user uses the macro STPUTC to add characters to the string. In
1578 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1579 * grown as necessary. When the user is done, she can just leave the
1580 * string there and refer to it using stackblock(). Or she can allocate
1581 * the space for it using grabstackstr(). If it is necessary to allow
1582 * someone else to use the stack temporarily and then continue to grow
1583 * the string, the user should use grabstack to allocate the space, and
1584 * then call ungrabstr(p) to return to the previous mode of operation.
1585 *
1586 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1587 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1588 * is space for at least one character.
1589 */
1590static void *
1591growstackstr(void)
1592{
1593 size_t len = stackblocksize();
1594 if (herefd >= 0 && len >= 1024) {
1595 full_write(herefd, stackblock(), len);
1596 return stackblock();
1597 }
1598 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001599 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001600}
1601
1602/*
1603 * Called from CHECKSTRSPACE.
1604 */
1605static char *
1606makestrspace(size_t newlen, char *p)
1607{
Denis Vlasenko01631112007-12-16 17:20:38 +00001608 size_t len = p - g_stacknxt;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001609 size_t size = stackblocksize();
1610
1611 for (;;) {
1612 size_t nleft;
1613
1614 size = stackblocksize();
1615 nleft = size - len;
1616 if (nleft >= newlen)
1617 break;
1618 growstackblock();
1619 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001620 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001621}
1622
1623static char *
1624stack_nputstr(const char *s, size_t n, char *p)
1625{
1626 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001627 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001628 return p;
1629}
1630
1631static char *
1632stack_putstr(const char *s, char *p)
1633{
1634 return stack_nputstr(s, strlen(s), p);
1635}
1636
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001637static char *
1638_STPUTC(int c, char *p)
1639{
1640 if (p == sstrend)
1641 p = growstackstr();
1642 *p++ = c;
1643 return p;
1644}
1645
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001646#define STARTSTACKSTR(p) ((p) = stackblock())
1647#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001648#define CHECKSTRSPACE(n, p) do { \
1649 char *q = (p); \
1650 size_t l = (n); \
1651 size_t m = sstrend - q; \
1652 if (l > m) \
1653 (p) = makestrspace(l, q); \
1654} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001655#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001656#define STACKSTRNUL(p) do { \
1657 if ((p) == sstrend) \
1658 (p) = growstackstr(); \
1659 *(p) = '\0'; \
1660} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001661#define STUNPUTC(p) (--(p))
1662#define STTOPC(p) ((p)[-1])
1663#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001664
1665#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001666#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001667#define stackstrend() ((void *)sstrend)
1668
1669
1670/* ============ String helpers */
1671
1672/*
1673 * prefix -- see if pfx is a prefix of string.
1674 */
1675static char *
1676prefix(const char *string, const char *pfx)
1677{
1678 while (*pfx) {
1679 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001680 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001681 }
1682 return (char *) string;
1683}
1684
1685/*
1686 * Check for a valid number. This should be elsewhere.
1687 */
1688static int
1689is_number(const char *p)
1690{
1691 do {
1692 if (!isdigit(*p))
1693 return 0;
1694 } while (*++p != '\0');
1695 return 1;
1696}
1697
1698/*
1699 * Convert a string of digits to an integer, printing an error message on
1700 * failure.
1701 */
1702static int
1703number(const char *s)
1704{
1705 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001706 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001707 return atoi(s);
1708}
1709
1710/*
1711 * Produce a possibly single quoted string suitable as input to the shell.
1712 * The return string is allocated on the stack.
1713 */
1714static char *
1715single_quote(const char *s)
1716{
1717 char *p;
1718
1719 STARTSTACKSTR(p);
1720
1721 do {
1722 char *q;
1723 size_t len;
1724
1725 len = strchrnul(s, '\'') - s;
1726
1727 q = p = makestrspace(len + 3, p);
1728
1729 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001730 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001731 *q++ = '\'';
1732 s += len;
1733
1734 STADJUST(q - p, p);
1735
Denys Vlasenkocd716832009-11-28 22:14:02 +01001736 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001737 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001738 len = 0;
1739 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001740
1741 q = p = makestrspace(len + 3, p);
1742
1743 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001744 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001745 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001746
1747 STADJUST(q - p, p);
1748 } while (*s);
1749
Denys Vlasenkocd716832009-11-28 22:14:02 +01001750 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001751
1752 return stackblock();
1753}
1754
1755
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001756/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001757
1758static char **argptr; /* argument list for builtin commands */
1759static char *optionarg; /* set by nextopt (like getopt) */
1760static char *optptr; /* used by nextopt */
1761
1762/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001763 * XXX - should get rid of. Have all builtins use getopt(3).
1764 * The library getopt must have the BSD extension static variable
1765 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001766 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001767 * Standard option processing (a la getopt) for builtin routines.
1768 * The only argument that is passed to nextopt is the option string;
1769 * the other arguments are unnecessary. It returns the character,
1770 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001771 */
1772static int
1773nextopt(const char *optstring)
1774{
1775 char *p;
1776 const char *q;
1777 char c;
1778
1779 p = optptr;
1780 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001781 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001782 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001783 if (p == NULL)
1784 return '\0';
1785 if (*p != '-')
1786 return '\0';
1787 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001788 return '\0';
1789 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001790 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001792 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001793 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001794 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001795 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001796 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001797 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001798 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001799 if (*++q == ':')
1800 q++;
1801 }
1802 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001803 if (*p == '\0') {
1804 p = *argptr++;
1805 if (p == NULL)
1806 ash_msg_and_raise_error("no arg for -%c option", c);
1807 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001808 optionarg = p;
1809 p = NULL;
1810 }
1811 optptr = p;
1812 return c;
1813}
1814
1815
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001816/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001817
Denis Vlasenko01631112007-12-16 17:20:38 +00001818/*
1819 * The parsefile structure pointed to by the global variable parsefile
1820 * contains information about the current file being read.
1821 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001822struct shparam {
1823 int nparam; /* # of positional parameters (without $0) */
1824#if ENABLE_ASH_GETOPTS
1825 int optind; /* next parameter to be processed by getopts */
1826 int optoff; /* used by getopts */
1827#endif
1828 unsigned char malloced; /* if parameter list dynamically allocated */
1829 char **p; /* parameter list */
1830};
1831
1832/*
1833 * Free the list of positional parameters.
1834 */
1835static void
1836freeparam(volatile struct shparam *param)
1837{
Denis Vlasenko01631112007-12-16 17:20:38 +00001838 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001839 char **ap, **ap1;
1840 ap = ap1 = param->p;
1841 while (*ap)
1842 free(*ap++);
1843 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001844 }
1845}
1846
1847#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001848static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001849#endif
1850
1851struct var {
1852 struct var *next; /* next entry in hash list */
1853 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001854 const char *var_text; /* name=value */
1855 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001856 /* the variable gets set/unset */
1857};
1858
1859struct localvar {
1860 struct localvar *next; /* next local variable in list */
1861 struct var *vp; /* the variable that was made local */
1862 int flags; /* saved flags */
1863 const char *text; /* saved text */
1864};
1865
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001866/* flags */
1867#define VEXPORT 0x01 /* variable is exported */
1868#define VREADONLY 0x02 /* variable cannot be modified */
1869#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1870#define VTEXTFIXED 0x08 /* text is statically allocated */
1871#define VSTACK 0x10 /* text is allocated on the stack */
1872#define VUNSET 0x20 /* the variable is not set */
1873#define VNOFUNC 0x40 /* don't call the callback function */
1874#define VNOSET 0x80 /* do not set variable - just readonly test */
1875#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001876#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001877# define VDYNAMIC 0x200 /* dynamic variable */
1878#else
1879# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001880#endif
1881
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001882
Denis Vlasenko01631112007-12-16 17:20:38 +00001883/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001884#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001885static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001886change_lc_all(const char *value)
1887{
1888 if (value && *value != '\0')
1889 setlocale(LC_ALL, value);
1890}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001891static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001892change_lc_ctype(const char *value)
1893{
1894 if (value && *value != '\0')
1895 setlocale(LC_CTYPE, value);
1896}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001897#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001898#if ENABLE_ASH_MAIL
1899static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001900static void changemail(const char *var_value) FAST_FUNC;
1901#else
1902# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001903#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001904static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001905#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001906static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001907#endif
1908
Denis Vlasenko01631112007-12-16 17:20:38 +00001909static const struct {
1910 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001911 const char *var_text;
1912 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001913} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001914 /*
1915 * Note: VEXPORT would not work correctly here for NOFORK applets:
1916 * some environment strings may be constant.
1917 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001918 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001919#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001920 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1921 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001922#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001923 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1924 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1925 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1926 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001927#if ENABLE_ASH_GETOPTS
Denis Vlasenko01631112007-12-16 17:20:38 +00001928 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001929#endif
1930#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001931 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001932#endif
1933#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001934 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1935 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001936#endif
1937#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001938 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001939#endif
1940};
1941
Denis Vlasenko0b769642008-07-24 07:54:57 +00001942struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001943
1944struct globals_var {
1945 struct shparam shellparam; /* $@ current positional parameters */
1946 struct redirtab *redirlist;
1947 int g_nullredirs;
1948 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1949 struct var *vartab[VTABSIZE];
1950 struct var varinit[ARRAY_SIZE(varinit_data)];
1951};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001952extern struct globals_var *const ash_ptr_to_globals_var;
1953#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001954#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001955//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001956#define g_nullredirs (G_var.g_nullredirs )
1957#define preverrout_fd (G_var.preverrout_fd)
1958#define vartab (G_var.vartab )
1959#define varinit (G_var.varinit )
1960#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001961 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001962 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1963 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001964 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001965 varinit[i].flags = varinit_data[i].flags; \
1966 varinit[i].var_text = varinit_data[i].var_text; \
1967 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001968 } \
1969} while (0)
1970
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001971#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001972#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001973# define vmail (&vifs)[1]
1974# define vmpath (&vmail)[1]
1975# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001976#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001977# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001978#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001979#define vps1 (&vpath)[1]
1980#define vps2 (&vps1)[1]
1981#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001982#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001983# define voptind (&vps4)[1]
1984# if ENABLE_ASH_RANDOM_SUPPORT
1985# define vrandom (&voptind)[1]
1986# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001987#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001988# if ENABLE_ASH_RANDOM_SUPPORT
1989# define vrandom (&vps4)[1]
1990# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001991#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001992
1993/*
1994 * The following macros access the values of the above variables.
1995 * They have to skip over the name. They return the null string
1996 * for unset variables.
1997 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001998#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001999#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002000#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002001# define mailval() (vmail.var_text + 5)
2002# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002003# define mpathset() ((vmpath.flags & VUNSET) == 0)
2004#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002005#define pathval() (vpath.var_text + 5)
2006#define ps1val() (vps1.var_text + 4)
2007#define ps2val() (vps2.var_text + 4)
2008#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002009#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002010# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002011#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002012
Denis Vlasenko01631112007-12-16 17:20:38 +00002013#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002014static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002015getoptsreset(const char *value)
2016{
2017 shellparam.optind = number(value);
2018 shellparam.optoff = -1;
2019}
2020#endif
2021
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002022/*
2023 * Compares two strings up to the first = or '\0'. The first
2024 * string must be terminated by '='; the second may be terminated by
2025 * either '=' or '\0'.
2026 */
2027static int
2028varcmp(const char *p, const char *q)
2029{
2030 int c, d;
2031
2032 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002033 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002034 goto out;
2035 p++;
2036 q++;
2037 }
2038 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002039 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002040 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002041 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002042 out:
2043 return c - d;
2044}
2045
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002046/*
2047 * Find the appropriate entry in the hash table from the name.
2048 */
2049static struct var **
2050hashvar(const char *p)
2051{
2052 unsigned hashval;
2053
2054 hashval = ((unsigned char) *p) << 4;
2055 while (*p && *p != '=')
2056 hashval += (unsigned char) *p++;
2057 return &vartab[hashval % VTABSIZE];
2058}
2059
2060static int
2061vpcmp(const void *a, const void *b)
2062{
2063 return varcmp(*(const char **)a, *(const char **)b);
2064}
2065
2066/*
2067 * This routine initializes the builtin variables.
2068 */
2069static void
2070initvar(void)
2071{
2072 struct var *vp;
2073 struct var *end;
2074 struct var **vpp;
2075
2076 /*
2077 * PS1 depends on uid
2078 */
2079#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002080 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002081#else
2082 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002083 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002084#endif
2085 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002086 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002087 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002088 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002089 vp->next = *vpp;
2090 *vpp = vp;
2091 } while (++vp < end);
2092}
2093
2094static struct var **
2095findvar(struct var **vpp, const char *name)
2096{
2097 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002098 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002099 break;
2100 }
2101 }
2102 return vpp;
2103}
2104
2105/*
2106 * Find the value of a variable. Returns NULL if not set.
2107 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002108static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002109lookupvar(const char *name)
2110{
2111 struct var *v;
2112
2113 v = *findvar(hashvar(name), name);
2114 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002115#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002116 /*
2117 * Dynamic variables are implemented roughly the same way they are
2118 * in bash. Namely, they're "special" so long as they aren't unset.
2119 * As soon as they're unset, they're no longer dynamic, and dynamic
2120 * lookup will no longer happen at that point. -- PFM.
2121 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002122 if (v->flags & VDYNAMIC)
2123 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002124#endif
2125 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002126 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002127 }
2128 return NULL;
2129}
2130
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002131static void reinit_unicode_for_ash(void)
2132{
2133 /* Unicode support should be activated even if LANG is set
2134 * _during_ shell execution, not only if it was set when
2135 * shell was started. Therefore, re-check LANG every time:
2136 */
2137 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2138 || ENABLE_UNICODE_USING_LOCALE
2139 ) {
2140 const char *s = lookupvar("LC_ALL");
2141 if (!s) s = lookupvar("LC_CTYPE");
2142 if (!s) s = lookupvar("LANG");
2143 reinit_unicode(s);
2144 }
2145}
2146
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002147/*
2148 * Search the environment of a builtin command.
2149 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002150static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002151bltinlookup(const char *name)
2152{
2153 struct strlist *sp;
2154
2155 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002156 if (varcmp(sp->text, name) == 0)
2157 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002158 }
2159 return lookupvar(name);
2160}
2161
2162/*
2163 * Same as setvar except that the variable and value are passed in
2164 * the first argument as name=value. Since the first argument will
2165 * be actually stored in the table, it should not be a string that
2166 * will go away.
2167 * Called with interrupts off.
2168 */
2169static void
2170setvareq(char *s, int flags)
2171{
2172 struct var *vp, **vpp;
2173
2174 vpp = hashvar(s);
2175 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2176 vp = *findvar(vpp, s);
2177 if (vp) {
2178 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2179 const char *n;
2180
2181 if (flags & VNOSAVE)
2182 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002183 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002184 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2185 }
2186
2187 if (flags & VNOSET)
2188 return;
2189
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002190 if (vp->var_func && !(flags & VNOFUNC))
2191 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002192
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002193 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2194 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002195
2196 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2197 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002198 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002199 if (flags & VNOSET)
2200 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002201 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002202 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002203 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002204 *vpp = vp;
2205 }
2206 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2207 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002208 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002209 vp->flags = flags;
2210}
2211
2212/*
2213 * Set the value of a variable. The flags argument is ored with the
2214 * flags of the variable. If val is NULL, the variable is unset.
2215 */
2216static void
2217setvar(const char *name, const char *val, int flags)
2218{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002219 const char *q;
2220 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002221 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002222 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002223 size_t vallen;
2224
2225 q = endofname(name);
2226 p = strchrnul(q, '=');
2227 namelen = p - name;
2228 if (!namelen || p != q)
2229 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2230 vallen = 0;
2231 if (val == NULL) {
2232 flags |= VUNSET;
2233 } else {
2234 vallen = strlen(val);
2235 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002236
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002237 INT_OFF;
2238 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002239 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002240 if (val) {
2241 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002242 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002243 }
2244 *p = '\0';
2245 setvareq(nameeq, flags | VNOSAVE);
2246 INT_ON;
2247}
2248
Denys Vlasenko03dad222010-01-12 23:29:57 +01002249static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002250setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002251{
2252 setvar(name, val, 0);
2253}
2254
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002255#if ENABLE_ASH_GETOPTS
2256/*
2257 * Safe version of setvar, returns 1 on success 0 on failure.
2258 */
2259static int
2260setvarsafe(const char *name, const char *val, int flags)
2261{
2262 int err;
2263 volatile int saveint;
2264 struct jmploc *volatile savehandler = exception_handler;
2265 struct jmploc jmploc;
2266
2267 SAVE_INT(saveint);
2268 if (setjmp(jmploc.loc))
2269 err = 1;
2270 else {
2271 exception_handler = &jmploc;
2272 setvar(name, val, flags);
2273 err = 0;
2274 }
2275 exception_handler = savehandler;
2276 RESTORE_INT(saveint);
2277 return err;
2278}
2279#endif
2280
2281/*
2282 * Unset the specified variable.
2283 */
2284static int
2285unsetvar(const char *s)
2286{
2287 struct var **vpp;
2288 struct var *vp;
2289 int retval;
2290
2291 vpp = findvar(hashvar(s), s);
2292 vp = *vpp;
2293 retval = 2;
2294 if (vp) {
2295 int flags = vp->flags;
2296
2297 retval = 1;
2298 if (flags & VREADONLY)
2299 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002300#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002301 vp->flags &= ~VDYNAMIC;
2302#endif
2303 if (flags & VUNSET)
2304 goto ok;
2305 if ((flags & VSTRFIXED) == 0) {
2306 INT_OFF;
2307 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002308 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002309 *vpp = vp->next;
2310 free(vp);
2311 INT_ON;
2312 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002313 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002314 vp->flags &= ~VEXPORT;
2315 }
2316 ok:
2317 retval = 0;
2318 }
2319 out:
2320 return retval;
2321}
2322
2323/*
2324 * Process a linked list of variable assignments.
2325 */
2326static void
2327listsetvar(struct strlist *list_set_var, int flags)
2328{
2329 struct strlist *lp = list_set_var;
2330
2331 if (!lp)
2332 return;
2333 INT_OFF;
2334 do {
2335 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002336 lp = lp->next;
2337 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002338 INT_ON;
2339}
2340
2341/*
2342 * Generate a list of variables satisfying the given conditions.
2343 */
2344static char **
2345listvars(int on, int off, char ***end)
2346{
2347 struct var **vpp;
2348 struct var *vp;
2349 char **ep;
2350 int mask;
2351
2352 STARTSTACKSTR(ep);
2353 vpp = vartab;
2354 mask = on | off;
2355 do {
2356 for (vp = *vpp; vp; vp = vp->next) {
2357 if ((vp->flags & mask) == on) {
2358 if (ep == stackstrend())
2359 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002360 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002361 }
2362 }
2363 } while (++vpp < vartab + VTABSIZE);
2364 if (ep == stackstrend())
2365 ep = growstackstr();
2366 if (end)
2367 *end = ep;
2368 *ep++ = NULL;
2369 return grabstackstr(ep);
2370}
2371
2372
2373/* ============ Path search helper
2374 *
2375 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002376 * of the path before the first call; path_advance will update
2377 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002378 * the possible path expansions in sequence. If an option (indicated by
2379 * a percent sign) appears in the path entry then the global variable
2380 * pathopt will be set to point to it; otherwise pathopt will be set to
2381 * NULL.
2382 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002383static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002384
2385static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002386path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002387{
2388 const char *p;
2389 char *q;
2390 const char *start;
2391 size_t len;
2392
2393 if (*path == NULL)
2394 return NULL;
2395 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002396 for (p = start; *p && *p != ':' && *p != '%'; p++)
2397 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002398 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2399 while (stackblocksize() < len)
2400 growstackblock();
2401 q = stackblock();
2402 if (p != start) {
2403 memcpy(q, start, p - start);
2404 q += p - start;
2405 *q++ = '/';
2406 }
2407 strcpy(q, name);
2408 pathopt = NULL;
2409 if (*p == '%') {
2410 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002411 while (*p && *p != ':')
2412 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002413 }
2414 if (*p == ':')
2415 *path = p + 1;
2416 else
2417 *path = NULL;
2418 return stalloc(len);
2419}
2420
2421
2422/* ============ Prompt */
2423
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002424static smallint doprompt; /* if set, prompt the user */
2425static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002426
2427#if ENABLE_FEATURE_EDITING
2428static line_input_t *line_input_state;
2429static const char *cmdedit_prompt;
2430static void
2431putprompt(const char *s)
2432{
2433 if (ENABLE_ASH_EXPAND_PRMT) {
2434 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002435 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002436 return;
2437 }
2438 cmdedit_prompt = s;
2439}
2440#else
2441static void
2442putprompt(const char *s)
2443{
2444 out2str(s);
2445}
2446#endif
2447
2448#if ENABLE_ASH_EXPAND_PRMT
2449/* expandstr() needs parsing machinery, so it is far away ahead... */
2450static const char *expandstr(const char *ps);
2451#else
2452#define expandstr(s) s
2453#endif
2454
2455static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002456setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002457{
2458 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002459 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2460
2461 if (!do_set)
2462 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002463
2464 needprompt = 0;
2465
2466 switch (whichprompt) {
2467 case 1:
2468 prompt = ps1val();
2469 break;
2470 case 2:
2471 prompt = ps2val();
2472 break;
2473 default: /* 0 */
2474 prompt = nullstr;
2475 }
2476#if ENABLE_ASH_EXPAND_PRMT
2477 setstackmark(&smark);
2478 stalloc(stackblocksize());
2479#endif
2480 putprompt(expandstr(prompt));
2481#if ENABLE_ASH_EXPAND_PRMT
2482 popstackmark(&smark);
2483#endif
2484}
2485
2486
2487/* ============ The cd and pwd commands */
2488
2489#define CD_PHYSICAL 1
2490#define CD_PRINT 2
2491
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002492static int
2493cdopt(void)
2494{
2495 int flags = 0;
2496 int i, j;
2497
2498 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002499 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002500 if (i != j) {
2501 flags ^= CD_PHYSICAL;
2502 j = i;
2503 }
2504 }
2505
2506 return flags;
2507}
2508
2509/*
2510 * Update curdir (the name of the current directory) in response to a
2511 * cd command.
2512 */
2513static const char *
2514updatepwd(const char *dir)
2515{
2516 char *new;
2517 char *p;
2518 char *cdcomppath;
2519 const char *lim;
2520
2521 cdcomppath = ststrdup(dir);
2522 STARTSTACKSTR(new);
2523 if (*dir != '/') {
2524 if (curdir == nullstr)
2525 return 0;
2526 new = stack_putstr(curdir, new);
2527 }
2528 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002529 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002530 if (*dir != '/') {
2531 if (new[-1] != '/')
2532 USTPUTC('/', new);
2533 if (new > lim && *lim == '/')
2534 lim++;
2535 } else {
2536 USTPUTC('/', new);
2537 cdcomppath++;
2538 if (dir[1] == '/' && dir[2] != '/') {
2539 USTPUTC('/', new);
2540 cdcomppath++;
2541 lim++;
2542 }
2543 }
2544 p = strtok(cdcomppath, "/");
2545 while (p) {
2546 switch (*p) {
2547 case '.':
2548 if (p[1] == '.' && p[2] == '\0') {
2549 while (new > lim) {
2550 STUNPUTC(new);
2551 if (new[-1] == '/')
2552 break;
2553 }
2554 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002555 }
2556 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002557 break;
2558 /* fall through */
2559 default:
2560 new = stack_putstr(p, new);
2561 USTPUTC('/', new);
2562 }
2563 p = strtok(0, "/");
2564 }
2565 if (new > lim)
2566 STUNPUTC(new);
2567 *new = 0;
2568 return stackblock();
2569}
2570
2571/*
2572 * Find out what the current directory is. If we already know the current
2573 * directory, this routine returns immediately.
2574 */
2575static char *
2576getpwd(void)
2577{
Denis Vlasenko01631112007-12-16 17:20:38 +00002578 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002579 return dir ? dir : nullstr;
2580}
2581
2582static void
2583setpwd(const char *val, int setold)
2584{
2585 char *oldcur, *dir;
2586
2587 oldcur = dir = curdir;
2588
2589 if (setold) {
2590 setvar("OLDPWD", oldcur, VEXPORT);
2591 }
2592 INT_OFF;
2593 if (physdir != nullstr) {
2594 if (physdir != oldcur)
2595 free(physdir);
2596 physdir = nullstr;
2597 }
2598 if (oldcur == val || !val) {
2599 char *s = getpwd();
2600 physdir = s;
2601 if (!val)
2602 dir = s;
2603 } else
2604 dir = ckstrdup(val);
2605 if (oldcur != dir && oldcur != nullstr) {
2606 free(oldcur);
2607 }
2608 curdir = dir;
2609 INT_ON;
2610 setvar("PWD", dir, VEXPORT);
2611}
2612
2613static void hashcd(void);
2614
2615/*
2616 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2617 * know that the current directory has changed.
2618 */
2619static int
2620docd(const char *dest, int flags)
2621{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002622 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002623 int err;
2624
2625 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2626
2627 INT_OFF;
2628 if (!(flags & CD_PHYSICAL)) {
2629 dir = updatepwd(dest);
2630 if (dir)
2631 dest = dir;
2632 }
2633 err = chdir(dest);
2634 if (err)
2635 goto out;
2636 setpwd(dir, 1);
2637 hashcd();
2638 out:
2639 INT_ON;
2640 return err;
2641}
2642
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002643static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002644cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002645{
2646 const char *dest;
2647 const char *path;
2648 const char *p;
2649 char c;
2650 struct stat statb;
2651 int flags;
2652
2653 flags = cdopt();
2654 dest = *argptr;
2655 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002656 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002657 else if (LONE_DASH(dest)) {
2658 dest = bltinlookup("OLDPWD");
2659 flags |= CD_PRINT;
2660 }
2661 if (!dest)
2662 dest = nullstr;
2663 if (*dest == '/')
2664 goto step7;
2665 if (*dest == '.') {
2666 c = dest[1];
2667 dotdot:
2668 switch (c) {
2669 case '\0':
2670 case '/':
2671 goto step6;
2672 case '.':
2673 c = dest[2];
2674 if (c != '.')
2675 goto dotdot;
2676 }
2677 }
2678 if (!*dest)
2679 dest = ".";
2680 path = bltinlookup("CDPATH");
2681 if (!path) {
2682 step6:
2683 step7:
2684 p = dest;
2685 goto docd;
2686 }
2687 do {
2688 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002689 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002690 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2691 if (c && c != ':')
2692 flags |= CD_PRINT;
2693 docd:
2694 if (!docd(p, flags))
2695 goto out;
2696 break;
2697 }
2698 } while (path);
2699 ash_msg_and_raise_error("can't cd to %s", dest);
2700 /* NOTREACHED */
2701 out:
2702 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002703 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002704 return 0;
2705}
2706
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002707static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002708pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002709{
2710 int flags;
2711 const char *dir = curdir;
2712
2713 flags = cdopt();
2714 if (flags) {
2715 if (physdir == nullstr)
2716 setpwd(dir, 0);
2717 dir = physdir;
2718 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002719 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002720 return 0;
2721}
2722
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002723
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002724/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002725
Denis Vlasenko834dee72008-10-07 09:18:30 +00002726
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002727#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002728
Eric Andersenc470f442003-07-28 09:56:35 +00002729/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002730#define CWORD 0 /* character is nothing special */
2731#define CNL 1 /* newline character */
2732#define CBACK 2 /* a backslash character */
2733#define CSQUOTE 3 /* single quote */
2734#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002735#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002736#define CBQUOTE 6 /* backwards single quote */
2737#define CVAR 7 /* a dollar sign */
2738#define CENDVAR 8 /* a '}' character */
2739#define CLP 9 /* a left paren in arithmetic */
2740#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002741#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002742#define CCTL 12 /* like CWORD, except it must be escaped */
2743#define CSPCL 13 /* these terminate a word */
2744#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002745
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002746#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002747#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002748# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002749#endif
2750
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002751#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002752
Mike Frysinger98c52642009-04-02 10:02:37 +00002753#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002754# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002755#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002756# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002757#endif
Denys Vlasenko068d3862009-11-29 01:41:11 +01002758static const uint16_t S_I_T[] = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002759#if ENABLE_ASH_ALIAS
2760 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2761#endif
2762 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2763 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2764 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2765 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2766 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2767 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2768 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2769 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2770 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2771 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2772 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002773#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002774 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2775 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2776 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2777#endif
2778#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002779};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002780/* Constants below must match table above */
2781enum {
2782#if ENABLE_ASH_ALIAS
2783 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2784#endif
2785 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2786 CNL_CNL_CNL_CNL , /* 2 */
2787 CWORD_CCTL_CCTL_CWORD , /* 3 */
2788 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2789 CVAR_CVAR_CWORD_CVAR , /* 5 */
2790 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2791 CSPCL_CWORD_CWORD_CLP , /* 7 */
2792 CSPCL_CWORD_CWORD_CRP , /* 8 */
2793 CBACK_CBACK_CCTL_CBACK , /* 9 */
2794 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2795 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2796 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2797 CWORD_CWORD_CWORD_CWORD , /* 13 */
2798 CCTL_CCTL_CCTL_CCTL , /* 14 */
2799};
Eric Andersen2870d962001-07-02 17:27:21 +00002800
Denys Vlasenkocd716832009-11-28 22:14:02 +01002801/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2802 * caller must ensure proper cast on it if c is *char_ptr!
2803 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002804/* Values for syntax param */
2805#define BASESYNTAX 0 /* not in quotes */
2806#define DQSYNTAX 1 /* in double quotes */
2807#define SQSYNTAX 2 /* in single quotes */
2808#define ARISYNTAX 3 /* in arithmetic */
2809#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002810
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002811#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002812
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002813static int
2814SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002815{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00002816 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Denys Vlasenkocd716832009-11-28 22:14:02 +01002817# if ENABLE_ASH_ALIAS
2818 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002819 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2820 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2821 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2822 11, 3 /* "}~" */
2823 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002824# else
2825 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002826 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2827 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2828 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2829 10, 2 /* "}~" */
2830 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002831# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002832 const char *s;
2833 int indx;
2834
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002835 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002836 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002837# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002838 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002839 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002840 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002841# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002842 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002843 /* Cast is purely for paranoia here,
2844 * just in case someone passed signed char to us */
2845 if ((unsigned char)c >= CTL_FIRST
2846 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002847 ) {
2848 return CCTL;
2849 }
2850 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002851 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002852 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002853 indx = syntax_index_table[s - spec_symbls];
2854 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002855 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002856}
2857
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002858#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002859
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002860static const uint8_t syntax_index_table[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002861 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002862 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2872 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2873 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2895 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2896 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2897 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2898 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2899 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2901 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2902 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2903 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2904 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2905 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2907 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2909 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2910 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2921 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2922 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2923 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2925 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2926 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2954 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2955 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2956 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2959 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2987 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2988 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2989 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2990 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2991 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2992 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2993 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2994 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2995 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2996 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2997 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2998 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2999 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003118 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003119# if ENABLE_ASH_ALIAS
3120 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3121# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003122};
3123
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003124# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003125
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003126#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003127
Eric Andersen2870d962001-07-02 17:27:21 +00003128
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003129/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003130
Denis Vlasenko131ae172007-02-18 13:00:19 +00003131#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003132
3133#define ALIASINUSE 1
3134#define ALIASDEAD 2
3135
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003136struct alias {
3137 struct alias *next;
3138 char *name;
3139 char *val;
3140 int flag;
3141};
3142
Denis Vlasenko01631112007-12-16 17:20:38 +00003143
3144static struct alias **atab; // [ATABSIZE];
3145#define INIT_G_alias() do { \
3146 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3147} while (0)
3148
Eric Andersen2870d962001-07-02 17:27:21 +00003149
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003150static struct alias **
3151__lookupalias(const char *name) {
3152 unsigned int hashval;
3153 struct alias **app;
3154 const char *p;
3155 unsigned int ch;
3156
3157 p = name;
3158
3159 ch = (unsigned char)*p;
3160 hashval = ch << 4;
3161 while (ch) {
3162 hashval += ch;
3163 ch = (unsigned char)*++p;
3164 }
3165 app = &atab[hashval % ATABSIZE];
3166
3167 for (; *app; app = &(*app)->next) {
3168 if (strcmp(name, (*app)->name) == 0) {
3169 break;
3170 }
3171 }
3172
3173 return app;
3174}
3175
3176static struct alias *
3177lookupalias(const char *name, int check)
3178{
3179 struct alias *ap = *__lookupalias(name);
3180
3181 if (check && ap && (ap->flag & ALIASINUSE))
3182 return NULL;
3183 return ap;
3184}
3185
3186static struct alias *
3187freealias(struct alias *ap)
3188{
3189 struct alias *next;
3190
3191 if (ap->flag & ALIASINUSE) {
3192 ap->flag |= ALIASDEAD;
3193 return ap;
3194 }
3195
3196 next = ap->next;
3197 free(ap->name);
3198 free(ap->val);
3199 free(ap);
3200 return next;
3201}
Eric Andersencb57d552001-06-28 07:25:16 +00003202
Eric Andersenc470f442003-07-28 09:56:35 +00003203static void
3204setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003205{
3206 struct alias *ap, **app;
3207
3208 app = __lookupalias(name);
3209 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003210 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003211 if (ap) {
3212 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003213 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003214 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003215 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003216 ap->flag &= ~ALIASDEAD;
3217 } else {
3218 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003219 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003220 ap->name = ckstrdup(name);
3221 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003222 /*ap->flag = 0; - ckzalloc did it */
3223 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003224 *app = ap;
3225 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003226 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003227}
3228
Eric Andersenc470f442003-07-28 09:56:35 +00003229static int
3230unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003231{
Eric Andersencb57d552001-06-28 07:25:16 +00003232 struct alias **app;
3233
3234 app = __lookupalias(name);
3235
3236 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003237 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003238 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003239 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003240 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003241 }
3242
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003243 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003244}
3245
Eric Andersenc470f442003-07-28 09:56:35 +00003246static void
3247rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003248{
Eric Andersencb57d552001-06-28 07:25:16 +00003249 struct alias *ap, **app;
3250 int i;
3251
Denis Vlasenkob012b102007-02-19 22:43:01 +00003252 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003253 for (i = 0; i < ATABSIZE; i++) {
3254 app = &atab[i];
3255 for (ap = *app; ap; ap = *app) {
3256 *app = freealias(*app);
3257 if (ap == *app) {
3258 app = &ap->next;
3259 }
3260 }
3261 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003262 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003263}
3264
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003265static void
3266printalias(const struct alias *ap)
3267{
3268 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3269}
3270
Eric Andersencb57d552001-06-28 07:25:16 +00003271/*
3272 * TODO - sort output
3273 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003274static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003275aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003276{
3277 char *n, *v;
3278 int ret = 0;
3279 struct alias *ap;
3280
Denis Vlasenko68404f12008-03-17 09:00:54 +00003281 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003282 int i;
3283
Denis Vlasenko68404f12008-03-17 09:00:54 +00003284 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003285 for (ap = atab[i]; ap; ap = ap->next) {
3286 printalias(ap);
3287 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003288 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003289 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003290 }
3291 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003292 v = strchr(n+1, '=');
3293 if (v == NULL) { /* n+1: funny ksh stuff */
3294 ap = *__lookupalias(n);
3295 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003296 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003297 ret = 1;
3298 } else
3299 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003300 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003301 *v++ = '\0';
3302 setalias(n, v);
3303 }
3304 }
3305
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003306 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003307}
3308
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003309static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003310unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003311{
3312 int i;
3313
3314 while ((i = nextopt("a")) != '\0') {
3315 if (i == 'a') {
3316 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003317 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003318 }
3319 }
3320 for (i = 0; *argptr; argptr++) {
3321 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003322 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003323 i = 1;
3324 }
3325 }
3326
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003327 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003328}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003329
Denis Vlasenko131ae172007-02-18 13:00:19 +00003330#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003331
Eric Andersenc470f442003-07-28 09:56:35 +00003332
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003333/* ============ jobs.c */
3334
3335/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003336#define FORK_FG 0
3337#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003338#define FORK_NOJOB 2
3339
3340/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003341#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3342#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3343#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003344
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003345/*
3346 * A job structure contains information about a job. A job is either a
3347 * single process or a set of processes contained in a pipeline. In the
3348 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3349 * array of pids.
3350 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003351struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003352 pid_t ps_pid; /* process id */
3353 int ps_status; /* last process status from wait() */
3354 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003355};
3356
3357struct job {
3358 struct procstat ps0; /* status of process */
3359 struct procstat *ps; /* status or processes when more than one */
3360#if JOBS
3361 int stopstatus; /* status of a stopped job */
3362#endif
3363 uint32_t
3364 nprocs: 16, /* number of processes */
3365 state: 8,
3366#define JOBRUNNING 0 /* at least one proc running */
3367#define JOBSTOPPED 1 /* all procs are stopped */
3368#define JOBDONE 2 /* all procs are completed */
3369#if JOBS
3370 sigint: 1, /* job was killed by SIGINT */
3371 jobctl: 1, /* job running under job control */
3372#endif
3373 waited: 1, /* true if this entry has been waited for */
3374 used: 1, /* true if this entry is in used */
3375 changed: 1; /* true if status has changed */
3376 struct job *prev_job; /* previous job */
3377};
3378
Denis Vlasenko68404f12008-03-17 09:00:54 +00003379static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003380static int forkshell(struct job *, union node *, int);
3381static int waitforjob(struct job *);
3382
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003383#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003384enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003385#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003386#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003387static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003388static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003389#endif
3390
3391/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003392 * Ignore a signal.
3393 */
3394static void
3395ignoresig(int signo)
3396{
3397 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3398 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3399 /* No, need to do it */
3400 signal(signo, SIG_IGN);
3401 }
3402 sigmode[signo - 1] = S_HARD_IGN;
3403}
3404
3405/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003406 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003407 */
3408static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003409signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003410{
3411 gotsig[signo - 1] = 1;
3412
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003413 if (signo == SIGINT && !trap[SIGINT]) {
3414 if (!suppress_int) {
3415 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003416 raise_interrupt(); /* does not return */
3417 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003418 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003419 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003420 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003421 }
3422}
3423
3424/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003425 * Set the signal handler for the specified signal. The routine figures
3426 * out what it should be set to.
3427 */
3428static void
3429setsignal(int signo)
3430{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003431 char *t;
3432 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003433 struct sigaction act;
3434
3435 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003436 new_act = S_DFL;
3437 if (t != NULL) { /* trap for this sig is set */
3438 new_act = S_CATCH;
3439 if (t[0] == '\0') /* trap is "": ignore this sig */
3440 new_act = S_IGN;
3441 }
3442
3443 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003444 switch (signo) {
3445 case SIGINT:
3446 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003447 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003448 break;
3449 case SIGQUIT:
3450#if DEBUG
3451 if (debug)
3452 break;
3453#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003454 /* man bash:
3455 * "In all cases, bash ignores SIGQUIT. Non-builtin
3456 * commands run by bash have signal handlers
3457 * set to the values inherited by the shell
3458 * from its parent". */
3459 new_act = S_IGN;
3460 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003461 case SIGTERM:
3462 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003463 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003464 break;
3465#if JOBS
3466 case SIGTSTP:
3467 case SIGTTOU:
3468 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003469 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003470 break;
3471#endif
3472 }
3473 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003474//TODO: if !rootshell, we reset SIGQUIT to DFL,
3475//whereas we have to restore it to what shell got on entry
3476//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003477
3478 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003479 cur_act = *t;
3480 if (cur_act == 0) {
3481 /* current setting is not yet known */
3482 if (sigaction(signo, NULL, &act)) {
3483 /* pretend it worked; maybe we should give a warning,
3484 * but other shells don't. We don't alter sigmode,
3485 * so we retry every time.
3486 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003487 return;
3488 }
3489 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003490 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003491 if (mflag
3492 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3493 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003494 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003495 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496 }
3497 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003498 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003499 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003500
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003501 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003502 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003503 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003504 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003505 break;
3506 case S_IGN:
3507 act.sa_handler = SIG_IGN;
3508 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003509 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003510
3511 /* flags and mask matter only if !DFL and !IGN, but we do it
3512 * for all cases for more deterministic behavior:
3513 */
3514 act.sa_flags = 0;
3515 sigfillset(&act.sa_mask);
3516
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003517 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003518
3519 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003520}
3521
3522/* mode flags for set_curjob */
3523#define CUR_DELETE 2
3524#define CUR_RUNNING 1
3525#define CUR_STOPPED 0
3526
3527/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003528#define DOWAIT_NONBLOCK WNOHANG
3529#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003530
3531#if JOBS
3532/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003533static int initialpgrp; //references:2
3534static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003535#endif
3536/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003537static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003538/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003539static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003540/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003541static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003542/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003543static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003544
3545static void
3546set_curjob(struct job *jp, unsigned mode)
3547{
3548 struct job *jp1;
3549 struct job **jpp, **curp;
3550
3551 /* first remove from list */
3552 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003553 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003554 jp1 = *jpp;
3555 if (jp1 == jp)
3556 break;
3557 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003558 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003559 *jpp = jp1->prev_job;
3560
3561 /* Then re-insert in correct position */
3562 jpp = curp;
3563 switch (mode) {
3564 default:
3565#if DEBUG
3566 abort();
3567#endif
3568 case CUR_DELETE:
3569 /* job being deleted */
3570 break;
3571 case CUR_RUNNING:
3572 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003573 * put after all stopped jobs.
3574 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003575 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003576 jp1 = *jpp;
3577#if JOBS
3578 if (!jp1 || jp1->state != JOBSTOPPED)
3579#endif
3580 break;
3581 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003582 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003583 /* FALLTHROUGH */
3584#if JOBS
3585 case CUR_STOPPED:
3586#endif
3587 /* newly stopped job - becomes curjob */
3588 jp->prev_job = *jpp;
3589 *jpp = jp;
3590 break;
3591 }
3592}
3593
3594#if JOBS || DEBUG
3595static int
3596jobno(const struct job *jp)
3597{
3598 return jp - jobtab + 1;
3599}
3600#endif
3601
3602/*
3603 * Convert a job name to a job structure.
3604 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003605#if !JOBS
3606#define getjob(name, getctl) getjob(name)
3607#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003608static struct job *
3609getjob(const char *name, int getctl)
3610{
3611 struct job *jp;
3612 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003613 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003614 unsigned num;
3615 int c;
3616 const char *p;
3617 char *(*match)(const char *, const char *);
3618
3619 jp = curjob;
3620 p = name;
3621 if (!p)
3622 goto currentjob;
3623
3624 if (*p != '%')
3625 goto err;
3626
3627 c = *++p;
3628 if (!c)
3629 goto currentjob;
3630
3631 if (!p[1]) {
3632 if (c == '+' || c == '%') {
3633 currentjob:
3634 err_msg = "No current job";
3635 goto check;
3636 }
3637 if (c == '-') {
3638 if (jp)
3639 jp = jp->prev_job;
3640 err_msg = "No previous job";
3641 check:
3642 if (!jp)
3643 goto err;
3644 goto gotit;
3645 }
3646 }
3647
3648 if (is_number(p)) {
3649 num = atoi(p);
Denys Vlasenko07f7ea72014-09-08 17:21:52 +02003650 if (num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003651 jp = jobtab + num - 1;
3652 if (jp->used)
3653 goto gotit;
3654 goto err;
3655 }
3656 }
3657
3658 match = prefix;
3659 if (*p == '?') {
3660 match = strstr;
3661 p++;
3662 }
3663
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003664 found = NULL;
3665 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003666 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003667 if (found)
3668 goto err;
3669 found = jp;
3670 err_msg = "%s: ambiguous";
3671 }
3672 jp = jp->prev_job;
3673 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003674 if (!found)
3675 goto err;
3676 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003677
3678 gotit:
3679#if JOBS
3680 err_msg = "job %s not created under job control";
3681 if (getctl && jp->jobctl == 0)
3682 goto err;
3683#endif
3684 return jp;
3685 err:
3686 ash_msg_and_raise_error(err_msg, name);
3687}
3688
3689/*
3690 * Mark a job structure as unused.
3691 */
3692static void
3693freejob(struct job *jp)
3694{
3695 struct procstat *ps;
3696 int i;
3697
3698 INT_OFF;
3699 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003700 if (ps->ps_cmd != nullstr)
3701 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003702 }
3703 if (jp->ps != &jp->ps0)
3704 free(jp->ps);
3705 jp->used = 0;
3706 set_curjob(jp, CUR_DELETE);
3707 INT_ON;
3708}
3709
3710#if JOBS
3711static void
3712xtcsetpgrp(int fd, pid_t pgrp)
3713{
3714 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003715 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003716}
3717
3718/*
3719 * Turn job control on and off.
3720 *
3721 * Note: This code assumes that the third arg to ioctl is a character
3722 * pointer, which is true on Berkeley systems but not System V. Since
3723 * System V doesn't have job control yet, this isn't a problem now.
3724 *
3725 * Called with interrupts off.
3726 */
3727static void
3728setjobctl(int on)
3729{
3730 int fd;
3731 int pgrp;
3732
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003733 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003734 return;
3735 if (on) {
3736 int ofd;
3737 ofd = fd = open(_PATH_TTY, O_RDWR);
3738 if (fd < 0) {
3739 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3740 * That sometimes helps to acquire controlling tty.
3741 * Obviously, a workaround for bugs when someone
3742 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003743 fd = 2;
3744 while (!isatty(fd))
3745 if (--fd < 0)
3746 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003747 }
3748 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003749 if (ofd >= 0)
3750 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003751 if (fd < 0)
3752 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003753 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003754 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003755 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003756 pgrp = tcgetpgrp(fd);
3757 if (pgrp < 0) {
3758 out:
3759 ash_msg("can't access tty; job control turned off");
3760 mflag = on = 0;
3761 goto close;
3762 }
3763 if (pgrp == getpgrp())
3764 break;
3765 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003766 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003767 initialpgrp = pgrp;
3768
3769 setsignal(SIGTSTP);
3770 setsignal(SIGTTOU);
3771 setsignal(SIGTTIN);
3772 pgrp = rootpid;
3773 setpgid(0, pgrp);
3774 xtcsetpgrp(fd, pgrp);
3775 } else {
3776 /* turning job control off */
3777 fd = ttyfd;
3778 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003779 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003780 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003781 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003782 setpgid(0, pgrp);
3783 setsignal(SIGTSTP);
3784 setsignal(SIGTTOU);
3785 setsignal(SIGTTIN);
3786 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003787 if (fd >= 0)
3788 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003789 fd = -1;
3790 }
3791 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003792 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003793}
3794
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003795static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003796killcmd(int argc, char **argv)
3797{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003798 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003799 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003800 do {
3801 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003802 /*
3803 * "kill %N" - job kill
3804 * Converting to pgrp / pid kill
3805 */
3806 struct job *jp;
3807 char *dst;
3808 int j, n;
3809
3810 jp = getjob(argv[i], 0);
3811 /*
3812 * In jobs started under job control, we signal
3813 * entire process group by kill -PGRP_ID.
3814 * This happens, f.e., in interactive shell.
3815 *
3816 * Otherwise, we signal each child via
3817 * kill PID1 PID2 PID3.
3818 * Testcases:
3819 * sh -c 'sleep 1|sleep 1 & kill %1'
3820 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3821 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3822 */
3823 n = jp->nprocs; /* can't be 0 (I hope) */
3824 if (jp->jobctl)
3825 n = 1;
3826 dst = alloca(n * sizeof(int)*4);
3827 argv[i] = dst;
3828 for (j = 0; j < n; j++) {
3829 struct procstat *ps = &jp->ps[j];
3830 /* Skip non-running and not-stopped members
3831 * (i.e. dead members) of the job
3832 */
3833 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3834 continue;
3835 /*
3836 * kill_main has matching code to expect
3837 * leading space. Needed to not confuse
3838 * negative pids with "kill -SIGNAL_NO" syntax
3839 */
3840 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3841 }
3842 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003843 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003844 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003845 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003846 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003847}
3848
3849static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003850showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003851{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003852 struct procstat *ps;
3853 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003854
Denys Vlasenko285ad152009-12-04 23:02:27 +01003855 psend = jp->ps + jp->nprocs;
3856 for (ps = jp->ps + 1; ps < psend; ps++)
3857 printf(" | %s", ps->ps_cmd);
3858 outcslow('\n', stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003859 flush_stdout_stderr();
3860}
3861
3862
3863static int
3864restartjob(struct job *jp, int mode)
3865{
3866 struct procstat *ps;
3867 int i;
3868 int status;
3869 pid_t pgid;
3870
3871 INT_OFF;
3872 if (jp->state == JOBDONE)
3873 goto out;
3874 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003875 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003876 if (mode == FORK_FG)
3877 xtcsetpgrp(ttyfd, pgid);
3878 killpg(pgid, SIGCONT);
3879 ps = jp->ps;
3880 i = jp->nprocs;
3881 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003882 if (WIFSTOPPED(ps->ps_status)) {
3883 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003884 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003885 ps++;
3886 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003887 out:
3888 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3889 INT_ON;
3890 return status;
3891}
3892
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003893static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003894fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003895{
3896 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003897 int mode;
3898 int retval;
3899
3900 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3901 nextopt(nullstr);
3902 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003903 do {
3904 jp = getjob(*argv, 1);
3905 if (mode == FORK_BG) {
3906 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003907 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003908 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003909 out1str(jp->ps[0].ps_cmd);
3910 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003911 retval = restartjob(jp, mode);
3912 } while (*argv && *++argv);
3913 return retval;
3914}
3915#endif
3916
3917static int
3918sprint_status(char *s, int status, int sigonly)
3919{
3920 int col;
3921 int st;
3922
3923 col = 0;
3924 if (!WIFEXITED(status)) {
3925#if JOBS
3926 if (WIFSTOPPED(status))
3927 st = WSTOPSIG(status);
3928 else
3929#endif
3930 st = WTERMSIG(status);
3931 if (sigonly) {
3932 if (st == SIGINT || st == SIGPIPE)
3933 goto out;
3934#if JOBS
3935 if (WIFSTOPPED(status))
3936 goto out;
3937#endif
3938 }
3939 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003940//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003941 col = fmtstr(s, 32, strsignal(st));
3942 if (WCOREDUMP(status)) {
3943 col += fmtstr(s + col, 16, " (core dumped)");
3944 }
3945 } else if (!sigonly) {
3946 st = WEXITSTATUS(status);
3947 if (st)
3948 col = fmtstr(s, 16, "Done(%d)", st);
3949 else
3950 col = fmtstr(s, 16, "Done");
3951 }
3952 out:
3953 return col;
3954}
3955
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003956static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003957dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003958{
3959 int pid;
3960 int status;
3961 struct job *jp;
3962 struct job *thisjob;
3963 int state;
3964
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003965 TRACE(("dowait(0x%x) called\n", wait_flags));
3966
3967 /* Do a wait system call. If job control is compiled in, we accept
3968 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3969 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003970 if (doing_jobctl)
3971 wait_flags |= WUNTRACED;
3972 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003973 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3974 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003975 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003976 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003977
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003978 INT_OFF;
3979 thisjob = NULL;
3980 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003981 struct procstat *ps;
3982 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003983 if (jp->state == JOBDONE)
3984 continue;
3985 state = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003986 ps = jp->ps;
3987 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003988 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003989 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003990 TRACE(("Job %d: changing status of proc %d "
3991 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003992 jobno(jp), pid, ps->ps_status, status));
3993 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003994 thisjob = jp;
3995 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003996 if (ps->ps_status == -1)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003997 state = JOBRUNNING;
3998#if JOBS
3999 if (state == JOBRUNNING)
4000 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004001 if (WIFSTOPPED(ps->ps_status)) {
4002 jp->stopstatus = ps->ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004003 state = JOBSTOPPED;
4004 }
4005#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004006 } while (++ps < psend);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004007 if (thisjob)
4008 goto gotjob;
4009 }
4010#if JOBS
4011 if (!WIFSTOPPED(status))
4012#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004013 jobless--;
4014 goto out;
4015
4016 gotjob:
4017 if (state != JOBRUNNING) {
4018 thisjob->changed = 1;
4019
4020 if (thisjob->state != state) {
4021 TRACE(("Job %d: changing state from %d to %d\n",
4022 jobno(thisjob), thisjob->state, state));
4023 thisjob->state = state;
4024#if JOBS
4025 if (state == JOBSTOPPED) {
4026 set_curjob(thisjob, CUR_STOPPED);
4027 }
4028#endif
4029 }
4030 }
4031
4032 out:
4033 INT_ON;
4034
4035 if (thisjob && thisjob == job) {
4036 char s[48 + 1];
4037 int len;
4038
4039 len = sprint_status(s, status, 1);
4040 if (len) {
4041 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004042 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004043 out2str(s);
4044 }
4045 }
4046 return pid;
4047}
4048
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004049static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004050blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004051{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004052 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004053 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004054 raise_exception(EXSIG);
4055 return pid;
4056}
4057
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004058#if JOBS
4059static void
4060showjob(FILE *out, struct job *jp, int mode)
4061{
4062 struct procstat *ps;
4063 struct procstat *psend;
4064 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004065 int indent_col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004066 char s[80];
4067
4068 ps = jp->ps;
4069
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004070 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004071 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004072 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073 return;
4074 }
4075
4076 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004077 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004078
4079 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004080 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004081 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004082 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004083
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004084 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004085 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004086
4087 psend = ps + jp->nprocs;
4088
4089 if (jp->state == JOBRUNNING) {
4090 strcpy(s + col, "Running");
4091 col += sizeof("Running") - 1;
4092 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004093 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004094 if (jp->state == JOBSTOPPED)
4095 status = jp->stopstatus;
4096 col += sprint_status(s + col, status, 0);
4097 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004098 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004099
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004100 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4101 * or prints several "PID | <cmdN>" lines,
4102 * depending on SHOW_PIDS bit.
4103 * We do not print status of individual processes
4104 * between PID and <cmdN>. bash does it, but not very well:
4105 * first line shows overall job status, not process status,
4106 * making it impossible to know 1st process status.
4107 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004108 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004109 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004111 s[0] = '\0';
4112 col = 33;
4113 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004114 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004115 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004116 fprintf(out, "%s%*c%s%s",
4117 s,
4118 33 - col >= 0 ? 33 - col : 0, ' ',
4119 ps == jp->ps ? "" : "| ",
4120 ps->ps_cmd
4121 );
4122 } while (++ps != psend);
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004123 outcslow('\n', out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004124
4125 jp->changed = 0;
4126
4127 if (jp->state == JOBDONE) {
4128 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4129 freejob(jp);
4130 }
4131}
4132
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004133/*
4134 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4135 * statuses have changed since the last call to showjobs.
4136 */
4137static void
4138showjobs(FILE *out, int mode)
4139{
4140 struct job *jp;
4141
Denys Vlasenko883cea42009-07-11 15:31:59 +02004142 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004144 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004145 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004146 continue;
4147
4148 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004149 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004150 showjob(out, jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004151 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004152 }
4153}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004154
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004155static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004156jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004157{
4158 int mode, m;
4159
4160 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004161 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004162 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004163 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004164 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004165 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004166 }
4167
4168 argv = argptr;
4169 if (*argv) {
4170 do
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004171 showjob(stdout, getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004172 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004173 } else {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004174 showjobs(stdout, mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004175 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004176
4177 return 0;
4178}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004179#endif /* JOBS */
4180
Michael Abbott359da5e2009-12-04 23:03:29 +01004181/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004182static int
4183getstatus(struct job *job)
4184{
4185 int status;
4186 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004187 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004188
Michael Abbott359da5e2009-12-04 23:03:29 +01004189 /* Fetch last member's status */
4190 ps = job->ps + job->nprocs - 1;
4191 status = ps->ps_status;
4192 if (pipefail) {
4193 /* "set -o pipefail" mode: use last _nonzero_ status */
4194 while (status == 0 && --ps >= job->ps)
4195 status = ps->ps_status;
4196 }
4197
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004198 retval = WEXITSTATUS(status);
4199 if (!WIFEXITED(status)) {
4200#if JOBS
4201 retval = WSTOPSIG(status);
4202 if (!WIFSTOPPED(status))
4203#endif
4204 {
4205 /* XXX: limits number of signals */
4206 retval = WTERMSIG(status);
4207#if JOBS
4208 if (retval == SIGINT)
4209 job->sigint = 1;
4210#endif
4211 }
4212 retval += 128;
4213 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004214 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004215 jobno(job), job->nprocs, status, retval));
4216 return retval;
4217}
4218
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004219static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004220waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004221{
4222 struct job *job;
4223 int retval;
4224 struct job *jp;
4225
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004226 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004227 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004228
4229 nextopt(nullstr);
4230 retval = 0;
4231
4232 argv = argptr;
4233 if (!*argv) {
4234 /* wait for all jobs */
4235 for (;;) {
4236 jp = curjob;
4237 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004238 if (!jp) /* no running procs */
4239 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004240 if (jp->state == JOBRUNNING)
4241 break;
4242 jp->waited = 1;
4243 jp = jp->prev_job;
4244 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004245 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004246 /* man bash:
4247 * "When bash is waiting for an asynchronous command via
4248 * the wait builtin, the reception of a signal for which a trap
4249 * has been set will cause the wait builtin to return immediately
4250 * with an exit status greater than 128, immediately after which
4251 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004252 *
4253 * blocking_wait_with_raise_on_sig raises signal handlers
4254 * if it gets no pid (pid < 0). However,
4255 * if child sends us a signal *and immediately exits*,
4256 * blocking_wait_with_raise_on_sig gets pid > 0
4257 * and does not handle pending_sig. Check this case: */
4258 if (pending_sig)
4259 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004260 }
4261 }
4262
4263 retval = 127;
4264 do {
4265 if (**argv != '%') {
4266 pid_t pid = number(*argv);
4267 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004268 while (1) {
4269 if (!job)
4270 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004271 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004272 break;
4273 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004274 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004275 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004276 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004277 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004278 /* loop until process terminated or stopped */
4279 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004280 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004281 job->waited = 1;
4282 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004283 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004284 } while (*++argv);
4285
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004286 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004287 return retval;
4288}
4289
4290static struct job *
4291growjobtab(void)
4292{
4293 size_t len;
4294 ptrdiff_t offset;
4295 struct job *jp, *jq;
4296
4297 len = njobs * sizeof(*jp);
4298 jq = jobtab;
4299 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4300
4301 offset = (char *)jp - (char *)jq;
4302 if (offset) {
4303 /* Relocate pointers */
4304 size_t l = len;
4305
4306 jq = (struct job *)((char *)jq + l);
4307 while (l) {
4308 l -= sizeof(*jp);
4309 jq--;
4310#define joff(p) ((struct job *)((char *)(p) + l))
4311#define jmove(p) (p) = (void *)((char *)(p) + offset)
4312 if (joff(jp)->ps == &jq->ps0)
4313 jmove(joff(jp)->ps);
4314 if (joff(jp)->prev_job)
4315 jmove(joff(jp)->prev_job);
4316 }
4317 if (curjob)
4318 jmove(curjob);
4319#undef joff
4320#undef jmove
4321 }
4322
4323 njobs += 4;
4324 jobtab = jp;
4325 jp = (struct job *)((char *)jp + len);
4326 jq = jp + 3;
4327 do {
4328 jq->used = 0;
4329 } while (--jq >= jp);
4330 return jp;
4331}
4332
4333/*
4334 * Return a new job structure.
4335 * Called with interrupts off.
4336 */
4337static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004338makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004339{
4340 int i;
4341 struct job *jp;
4342
4343 for (i = njobs, jp = jobtab; ; jp++) {
4344 if (--i < 0) {
4345 jp = growjobtab();
4346 break;
4347 }
4348 if (jp->used == 0)
4349 break;
4350 if (jp->state != JOBDONE || !jp->waited)
4351 continue;
4352#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004353 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004354 continue;
4355#endif
4356 freejob(jp);
4357 break;
4358 }
4359 memset(jp, 0, sizeof(*jp));
4360#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004361 /* jp->jobctl is a bitfield.
4362 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004363 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004364 jp->jobctl = 1;
4365#endif
4366 jp->prev_job = curjob;
4367 curjob = jp;
4368 jp->used = 1;
4369 jp->ps = &jp->ps0;
4370 if (nprocs > 1) {
4371 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4372 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004373 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004374 jobno(jp)));
4375 return jp;
4376}
4377
4378#if JOBS
4379/*
4380 * Return a string identifying a command (to be printed by the
4381 * jobs command).
4382 */
4383static char *cmdnextc;
4384
4385static void
4386cmdputs(const char *s)
4387{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004388 static const char vstype[VSTYPE + 1][3] = {
4389 "", "}", "-", "+", "?", "=",
4390 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004391 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004392 };
4393
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004394 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004395 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004396 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004397 unsigned char c;
4398 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004399 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004400
Denys Vlasenko46a14772009-12-10 21:27:13 +01004401 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004402 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4403 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004404 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004405 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004406 switch (c) {
4407 case CTLESC:
4408 c = *p++;
4409 break;
4410 case CTLVAR:
4411 subtype = *p++;
4412 if ((subtype & VSTYPE) == VSLENGTH)
4413 str = "${#";
4414 else
4415 str = "${";
4416 if (!(subtype & VSQUOTE) == !(quoted & 1))
4417 goto dostr;
4418 quoted ^= 1;
4419 c = '"';
4420 break;
4421 case CTLENDVAR:
4422 str = "\"}" + !(quoted & 1);
4423 quoted >>= 1;
4424 subtype = 0;
4425 goto dostr;
4426 case CTLBACKQ:
4427 str = "$(...)";
4428 goto dostr;
4429 case CTLBACKQ+CTLQUOTE:
4430 str = "\"$(...)\"";
4431 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004432#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004433 case CTLARI:
4434 str = "$((";
4435 goto dostr;
4436 case CTLENDARI:
4437 str = "))";
4438 goto dostr;
4439#endif
4440 case CTLQUOTEMARK:
4441 quoted ^= 1;
4442 c = '"';
4443 break;
4444 case '=':
4445 if (subtype == 0)
4446 break;
4447 if ((subtype & VSTYPE) != VSNORMAL)
4448 quoted <<= 1;
4449 str = vstype[subtype & VSTYPE];
4450 if (subtype & VSNUL)
4451 c = ':';
4452 else
4453 goto checkstr;
4454 break;
4455 case '\'':
4456 case '\\':
4457 case '"':
4458 case '$':
4459 /* These can only happen inside quotes */
4460 cc[0] = c;
4461 str = cc;
4462 c = '\\';
4463 break;
4464 default:
4465 break;
4466 }
4467 USTPUTC(c, nextc);
4468 checkstr:
4469 if (!str)
4470 continue;
4471 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004472 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004473 USTPUTC(c, nextc);
4474 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004475 } /* while *p++ not NUL */
4476
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004477 if (quoted & 1) {
4478 USTPUTC('"', nextc);
4479 }
4480 *nextc = 0;
4481 cmdnextc = nextc;
4482}
4483
4484/* cmdtxt() and cmdlist() call each other */
4485static void cmdtxt(union node *n);
4486
4487static void
4488cmdlist(union node *np, int sep)
4489{
4490 for (; np; np = np->narg.next) {
4491 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004492 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004493 cmdtxt(np);
4494 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004495 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004496 }
4497}
4498
4499static void
4500cmdtxt(union node *n)
4501{
4502 union node *np;
4503 struct nodelist *lp;
4504 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004505
4506 if (!n)
4507 return;
4508 switch (n->type) {
4509 default:
4510#if DEBUG
4511 abort();
4512#endif
4513 case NPIPE:
4514 lp = n->npipe.cmdlist;
4515 for (;;) {
4516 cmdtxt(lp->n);
4517 lp = lp->next;
4518 if (!lp)
4519 break;
4520 cmdputs(" | ");
4521 }
4522 break;
4523 case NSEMI:
4524 p = "; ";
4525 goto binop;
4526 case NAND:
4527 p = " && ";
4528 goto binop;
4529 case NOR:
4530 p = " || ";
4531 binop:
4532 cmdtxt(n->nbinary.ch1);
4533 cmdputs(p);
4534 n = n->nbinary.ch2;
4535 goto donode;
4536 case NREDIR:
4537 case NBACKGND:
4538 n = n->nredir.n;
4539 goto donode;
4540 case NNOT:
4541 cmdputs("!");
4542 n = n->nnot.com;
4543 donode:
4544 cmdtxt(n);
4545 break;
4546 case NIF:
4547 cmdputs("if ");
4548 cmdtxt(n->nif.test);
4549 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004551 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004552 cmdputs("; else ");
4553 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004554 } else {
4555 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004556 }
4557 p = "; fi";
4558 goto dotail;
4559 case NSUBSHELL:
4560 cmdputs("(");
4561 n = n->nredir.n;
4562 p = ")";
4563 goto dotail;
4564 case NWHILE:
4565 p = "while ";
4566 goto until;
4567 case NUNTIL:
4568 p = "until ";
4569 until:
4570 cmdputs(p);
4571 cmdtxt(n->nbinary.ch1);
4572 n = n->nbinary.ch2;
4573 p = "; done";
4574 dodo:
4575 cmdputs("; do ");
4576 dotail:
4577 cmdtxt(n);
4578 goto dotail2;
4579 case NFOR:
4580 cmdputs("for ");
4581 cmdputs(n->nfor.var);
4582 cmdputs(" in ");
4583 cmdlist(n->nfor.args, 1);
4584 n = n->nfor.body;
4585 p = "; done";
4586 goto dodo;
4587 case NDEFUN:
4588 cmdputs(n->narg.text);
4589 p = "() { ... }";
4590 goto dotail2;
4591 case NCMD:
4592 cmdlist(n->ncmd.args, 1);
4593 cmdlist(n->ncmd.redirect, 0);
4594 break;
4595 case NARG:
4596 p = n->narg.text;
4597 dotail2:
4598 cmdputs(p);
4599 break;
4600 case NHERE:
4601 case NXHERE:
4602 p = "<<...";
4603 goto dotail2;
4604 case NCASE:
4605 cmdputs("case ");
4606 cmdputs(n->ncase.expr->narg.text);
4607 cmdputs(" in ");
4608 for (np = n->ncase.cases; np; np = np->nclist.next) {
4609 cmdtxt(np->nclist.pattern);
4610 cmdputs(") ");
4611 cmdtxt(np->nclist.body);
4612 cmdputs(";; ");
4613 }
4614 p = "esac";
4615 goto dotail2;
4616 case NTO:
4617 p = ">";
4618 goto redir;
4619 case NCLOBBER:
4620 p = ">|";
4621 goto redir;
4622 case NAPPEND:
4623 p = ">>";
4624 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004625#if ENABLE_ASH_BASH_COMPAT
4626 case NTO2:
4627#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004628 case NTOFD:
4629 p = ">&";
4630 goto redir;
4631 case NFROM:
4632 p = "<";
4633 goto redir;
4634 case NFROMFD:
4635 p = "<&";
4636 goto redir;
4637 case NFROMTO:
4638 p = "<>";
4639 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004640 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004641 cmdputs(p);
4642 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004643 cmdputs(utoa(n->ndup.dupfd));
4644 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004645 }
4646 n = n->nfile.fname;
4647 goto donode;
4648 }
4649}
4650
4651static char *
4652commandtext(union node *n)
4653{
4654 char *name;
4655
4656 STARTSTACKSTR(cmdnextc);
4657 cmdtxt(n);
4658 name = stackblock();
4659 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4660 name, cmdnextc, cmdnextc));
4661 return ckstrdup(name);
4662}
4663#endif /* JOBS */
4664
4665/*
4666 * Fork off a subshell. If we are doing job control, give the subshell its
4667 * own process group. Jp is a job structure that the job is to be added to.
4668 * N is the command that will be evaluated by the child. Both jp and n may
4669 * be NULL. The mode parameter can be one of the following:
4670 * FORK_FG - Fork off a foreground process.
4671 * FORK_BG - Fork off a background process.
4672 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4673 * process group even if job control is on.
4674 *
4675 * When job control is turned off, background processes have their standard
4676 * input redirected to /dev/null (except for the second and later processes
4677 * in a pipeline).
4678 *
4679 * Called with interrupts off.
4680 */
4681/*
4682 * Clear traps on a fork.
4683 */
4684static void
4685clear_traps(void)
4686{
4687 char **tp;
4688
4689 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004690 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004691 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004692 if (trap_ptr == trap)
4693 free(*tp);
4694 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004695 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004696 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004697 setsignal(tp - trap);
4698 INT_ON;
4699 }
4700 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004701 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004702}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004703
4704/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004705static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004706
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004707/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004708static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004709forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004710{
4711 int oldlvl;
4712
4713 TRACE(("Child shell %d\n", getpid()));
4714 oldlvl = shlvl;
4715 shlvl++;
4716
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004717 /* man bash: "Non-builtin commands run by bash have signal handlers
4718 * set to the values inherited by the shell from its parent".
4719 * Do we do it correctly? */
4720
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004721 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004722
4723 if (mode == FORK_NOJOB /* is it `xxx` ? */
4724 && n && n->type == NCMD /* is it single cmd? */
4725 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004726 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004727 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4728 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4729 ) {
4730 TRACE(("Trap hack\n"));
4731 /* Awful hack for `trap` or $(trap).
4732 *
4733 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4734 * contains an example where "trap" is executed in a subshell:
4735 *
4736 * save_traps=$(trap)
4737 * ...
4738 * eval "$save_traps"
4739 *
4740 * Standard does not say that "trap" in subshell shall print
4741 * parent shell's traps. It only says that its output
4742 * must have suitable form, but then, in the above example
4743 * (which is not supposed to be normative), it implies that.
4744 *
4745 * bash (and probably other shell) does implement it
4746 * (traps are reset to defaults, but "trap" still shows them),
4747 * but as a result, "trap" logic is hopelessly messed up:
4748 *
4749 * # trap
4750 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4751 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4752 * # true | trap <--- trap is in subshell - no output (ditto)
4753 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4754 * trap -- 'echo Ho' SIGWINCH
4755 * # echo `(trap)` <--- in subshell in subshell - output
4756 * trap -- 'echo Ho' SIGWINCH
4757 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4758 * trap -- 'echo Ho' SIGWINCH
4759 *
4760 * The rules when to forget and when to not forget traps
4761 * get really complex and nonsensical.
4762 *
4763 * Our solution: ONLY bare $(trap) or `trap` is special.
4764 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004765 /* Save trap handler strings for trap builtin to print */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004766 trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004767 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004768 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004769 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004770#if JOBS
4771 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004772 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004773 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004774 pid_t pgrp;
4775
4776 if (jp->nprocs == 0)
4777 pgrp = getpid();
4778 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004779 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004780 /* this can fail because we are doing it in the parent also */
4781 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004782 if (mode == FORK_FG)
4783 xtcsetpgrp(ttyfd, pgrp);
4784 setsignal(SIGTSTP);
4785 setsignal(SIGTTOU);
4786 } else
4787#endif
4788 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004789 /* man bash: "When job control is not in effect,
4790 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004791 ignoresig(SIGINT);
4792 ignoresig(SIGQUIT);
4793 if (jp->nprocs == 0) {
4794 close(0);
4795 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004796 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004797 }
4798 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004799 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004800 if (iflag) { /* why if iflag only? */
4801 setsignal(SIGINT);
4802 setsignal(SIGTERM);
4803 }
4804 /* man bash:
4805 * "In all cases, bash ignores SIGQUIT. Non-builtin
4806 * commands run by bash have signal handlers
4807 * set to the values inherited by the shell
4808 * from its parent".
4809 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004810 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004811 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004812#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004813 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004814 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004815 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004816 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004817 /* "jobs": we do not want to clear job list for it,
4818 * instead we remove only _its_ own_ job from job list.
4819 * This makes "jobs .... | cat" more useful.
4820 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004821 freejob(curjob);
4822 return;
4823 }
4824#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004825 for (jp = curjob; jp; jp = jp->prev_job)
4826 freejob(jp);
4827 jobless = 0;
4828}
4829
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004830/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004831#if !JOBS
4832#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4833#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004834static void
4835forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4836{
4837 TRACE(("In parent shell: child = %d\n", pid));
4838 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004839 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4840 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004841 jobless++;
4842 return;
4843 }
4844#if JOBS
4845 if (mode != FORK_NOJOB && jp->jobctl) {
4846 int pgrp;
4847
4848 if (jp->nprocs == 0)
4849 pgrp = pid;
4850 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004851 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004852 /* This can fail because we are doing it in the child also */
4853 setpgid(pid, pgrp);
4854 }
4855#endif
4856 if (mode == FORK_BG) {
4857 backgndpid = pid; /* set $! */
4858 set_curjob(jp, CUR_RUNNING);
4859 }
4860 if (jp) {
4861 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004862 ps->ps_pid = pid;
4863 ps->ps_status = -1;
4864 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004865#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004866 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004867 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004868#endif
4869 }
4870}
4871
4872static int
4873forkshell(struct job *jp, union node *n, int mode)
4874{
4875 int pid;
4876
4877 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4878 pid = fork();
4879 if (pid < 0) {
4880 TRACE(("Fork failed, errno=%d", errno));
4881 if (jp)
4882 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004883 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004884 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004885 if (pid == 0) {
4886 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004887 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004888 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004889 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004890 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004891 return pid;
4892}
4893
4894/*
4895 * Wait for job to finish.
4896 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004897 * Under job control we have the problem that while a child process
4898 * is running interrupts generated by the user are sent to the child
4899 * but not to the shell. This means that an infinite loop started by
4900 * an interactive user may be hard to kill. With job control turned off,
4901 * an interactive user may place an interactive program inside a loop.
4902 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004903 * these interrupts to also abort the loop. The approach we take here
4904 * is to have the shell ignore interrupt signals while waiting for a
4905 * foreground process to terminate, and then send itself an interrupt
4906 * signal if the child process was terminated by an interrupt signal.
4907 * Unfortunately, some programs want to do a bit of cleanup and then
4908 * exit on interrupt; unless these processes terminate themselves by
4909 * sending a signal to themselves (instead of calling exit) they will
4910 * confuse this approach.
4911 *
4912 * Called with interrupts off.
4913 */
4914static int
4915waitforjob(struct job *jp)
4916{
4917 int st;
4918
4919 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004920
4921 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004922 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004923 /* In non-interactive shells, we _can_ get
4924 * a keyboard signal here and be EINTRed,
4925 * but we just loop back, waiting for command to complete.
4926 *
4927 * man bash:
4928 * "If bash is waiting for a command to complete and receives
4929 * a signal for which a trap has been set, the trap
4930 * will not be executed until the command completes."
4931 *
4932 * Reality is that even if trap is not set, bash
4933 * will not act on the signal until command completes.
4934 * Try this. sleep5intoff.c:
4935 * #include <signal.h>
4936 * #include <unistd.h>
4937 * int main() {
4938 * sigset_t set;
4939 * sigemptyset(&set);
4940 * sigaddset(&set, SIGINT);
4941 * sigaddset(&set, SIGQUIT);
4942 * sigprocmask(SIG_BLOCK, &set, NULL);
4943 * sleep(5);
4944 * return 0;
4945 * }
4946 * $ bash -c './sleep5intoff; echo hi'
4947 * ^C^C^C^C <--- pressing ^C once a second
4948 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004949 * $ bash -c './sleep5intoff; echo hi'
4950 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4951 * $ _
4952 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004953 dowait(DOWAIT_BLOCK, jp);
4954 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004955 INT_ON;
4956
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004957 st = getstatus(jp);
4958#if JOBS
4959 if (jp->jobctl) {
4960 xtcsetpgrp(ttyfd, rootpid);
4961 /*
4962 * This is truly gross.
4963 * If we're doing job control, then we did a TIOCSPGRP which
4964 * caused us (the shell) to no longer be in the controlling
4965 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4966 * intuit from the subprocess exit status whether a SIGINT
4967 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4968 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004969 if (jp->sigint) /* TODO: do the same with all signals */
4970 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004971 }
4972 if (jp->state == JOBDONE)
4973#endif
4974 freejob(jp);
4975 return st;
4976}
4977
4978/*
4979 * return 1 if there are stopped jobs, otherwise 0
4980 */
4981static int
4982stoppedjobs(void)
4983{
4984 struct job *jp;
4985 int retval;
4986
4987 retval = 0;
4988 if (job_warning)
4989 goto out;
4990 jp = curjob;
4991 if (jp && jp->state == JOBSTOPPED) {
4992 out2str("You have stopped jobs.\n");
4993 job_warning = 2;
4994 retval++;
4995 }
4996 out:
4997 return retval;
4998}
4999
5000
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005001/* ============ redir.c
5002 *
5003 * Code for dealing with input/output redirection.
5004 */
5005
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005006#undef EMPTY
5007#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005008#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005009#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005010
5011/*
5012 * Open a file in noclobber mode.
5013 * The code was copied from bash.
5014 */
5015static int
5016noclobberopen(const char *fname)
5017{
5018 int r, fd;
5019 struct stat finfo, finfo2;
5020
5021 /*
5022 * If the file exists and is a regular file, return an error
5023 * immediately.
5024 */
5025 r = stat(fname, &finfo);
5026 if (r == 0 && S_ISREG(finfo.st_mode)) {
5027 errno = EEXIST;
5028 return -1;
5029 }
5030
5031 /*
5032 * If the file was not present (r != 0), make sure we open it
5033 * exclusively so that if it is created before we open it, our open
5034 * will fail. Make sure that we do not truncate an existing file.
5035 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5036 * file was not a regular file, we leave O_EXCL off.
5037 */
5038 if (r != 0)
5039 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5040 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5041
5042 /* If the open failed, return the file descriptor right away. */
5043 if (fd < 0)
5044 return fd;
5045
5046 /*
5047 * OK, the open succeeded, but the file may have been changed from a
5048 * non-regular file to a regular file between the stat and the open.
5049 * We are assuming that the O_EXCL open handles the case where FILENAME
5050 * did not exist and is symlinked to an existing file between the stat
5051 * and open.
5052 */
5053
5054 /*
5055 * If we can open it and fstat the file descriptor, and neither check
5056 * revealed that it was a regular file, and the file has not been
5057 * replaced, return the file descriptor.
5058 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005059 if (fstat(fd, &finfo2) == 0
5060 && !S_ISREG(finfo2.st_mode)
5061 && finfo.st_dev == finfo2.st_dev
5062 && finfo.st_ino == finfo2.st_ino
5063 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005064 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005065 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005066
5067 /* The file has been replaced. badness. */
5068 close(fd);
5069 errno = EEXIST;
5070 return -1;
5071}
5072
5073/*
5074 * Handle here documents. Normally we fork off a process to write the
5075 * data to a pipe. If the document is short, we can stuff the data in
5076 * the pipe without forking.
5077 */
5078/* openhere needs this forward reference */
5079static void expandhere(union node *arg, int fd);
5080static int
5081openhere(union node *redir)
5082{
5083 int pip[2];
5084 size_t len = 0;
5085
5086 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005087 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005088 if (redir->type == NHERE) {
5089 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005090 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005091 full_write(pip[1], redir->nhere.doc->narg.text, len);
5092 goto out;
5093 }
5094 }
5095 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005096 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005097 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005098 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5099 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5100 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5101 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005102 signal(SIGPIPE, SIG_DFL);
5103 if (redir->type == NHERE)
5104 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005105 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005106 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005107 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005108 }
5109 out:
5110 close(pip[1]);
5111 return pip[0];
5112}
5113
5114static int
5115openredirect(union node *redir)
5116{
5117 char *fname;
5118 int f;
5119
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02005120 fname = redir->nfile.expfname;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005121 switch (redir->nfile.type) {
5122 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005123 f = open(fname, O_RDONLY);
5124 if (f < 0)
5125 goto eopen;
5126 break;
5127 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005128 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005129 if (f < 0)
5130 goto ecreate;
5131 break;
5132 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005133#if ENABLE_ASH_BASH_COMPAT
5134 case NTO2:
5135#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005136 /* Take care of noclobber mode. */
5137 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005138 f = noclobberopen(fname);
5139 if (f < 0)
5140 goto ecreate;
5141 break;
5142 }
5143 /* FALLTHROUGH */
5144 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005145 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5146 if (f < 0)
5147 goto ecreate;
5148 break;
5149 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005150 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5151 if (f < 0)
5152 goto ecreate;
5153 break;
5154 default:
5155#if DEBUG
5156 abort();
5157#endif
5158 /* Fall through to eliminate warning. */
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005159/* Our single caller does this itself */
Denis Vlasenko0b769642008-07-24 07:54:57 +00005160// case NTOFD:
5161// case NFROMFD:
5162// f = -1;
5163// break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005164 case NHERE:
5165 case NXHERE:
5166 f = openhere(redir);
5167 break;
5168 }
5169
5170 return f;
5171 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005172 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005173 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005174 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005175}
5176
5177/*
5178 * Copy a file descriptor to be >= to. Returns -1
5179 * if the source file descriptor is closed, EMPTY if there are no unused
5180 * file descriptors left.
5181 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005182/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5183 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005184enum {
5185 COPYFD_EXACT = (int)~(INT_MAX),
5186 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5187};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005188static int
5189copyfd(int from, int to)
5190{
5191 int newfd;
5192
Denis Vlasenko5a867312008-07-24 19:46:38 +00005193 if (to & COPYFD_EXACT) {
5194 to &= ~COPYFD_EXACT;
5195 /*if (from != to)*/
5196 newfd = dup2(from, to);
5197 } else {
5198 newfd = fcntl(from, F_DUPFD, to);
5199 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005200 if (newfd < 0) {
5201 if (errno == EMFILE)
5202 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005203 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005204 ash_msg_and_raise_error("%d: %m", from);
5205 }
5206 return newfd;
5207}
5208
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005209/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005210struct two_fd_t {
5211 int orig, copy;
5212};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005213struct redirtab {
5214 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005215 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005216 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005217 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005218};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005219#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005220
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005221static int need_to_remember(struct redirtab *rp, int fd)
5222{
5223 int i;
5224
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005225 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005226 return 0;
5227
5228 for (i = 0; i < rp->pair_count; i++) {
5229 if (rp->two_fd[i].orig == fd) {
5230 /* already remembered */
5231 return 0;
5232 }
5233 }
5234 return 1;
5235}
5236
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005237/* "hidden" fd is a fd used to read scripts, or a copy of such */
5238static int is_hidden_fd(struct redirtab *rp, int fd)
5239{
5240 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005241 struct parsefile *pf;
5242
5243 if (fd == -1)
5244 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005245 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005246 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005247 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005248 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005249 * $ ash # running ash interactively
5250 * $ . ./script.sh
5251 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005252 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005253 * it's still ok to use it: "read" builtin uses it,
5254 * why should we cripple "exec" builtin?
5255 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005256 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005257 return 1;
5258 }
5259 pf = pf->prev;
5260 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005261
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005262 if (!rp)
5263 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005264 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005265 fd |= COPYFD_RESTORE;
5266 for (i = 0; i < rp->pair_count; i++) {
5267 if (rp->two_fd[i].copy == fd) {
5268 return 1;
5269 }
5270 }
5271 return 0;
5272}
5273
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005274/*
5275 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5276 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005277 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005278 */
5279/* flags passed to redirect */
5280#define REDIR_PUSH 01 /* save previous values of file descriptors */
5281#define REDIR_SAVEFD2 03 /* set preverrout */
5282static void
5283redirect(union node *redir, int flags)
5284{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005285 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005286 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005287 int i;
5288 int fd;
5289 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005290 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005291
Denis Vlasenko01631112007-12-16 17:20:38 +00005292 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005293 if (!redir) {
5294 return;
5295 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005296
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005297 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005298 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005299 INT_OFF;
5300 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005301 union node *tmp = redir;
5302 do {
5303 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005304#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005305 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005306 sv_pos++;
5307#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005308 tmp = tmp->nfile.next;
5309 } while (tmp);
5310 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005311 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005312 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005313 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005314 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005315 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005316 while (sv_pos > 0) {
5317 sv_pos--;
5318 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5319 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005320 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005321
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005322 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005323 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005324 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005325 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005326 right_fd = redir->ndup.dupfd;
5327 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005328 /* redirect from/to same file descriptor? */
5329 if (right_fd == fd)
5330 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005331 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005332 if (is_hidden_fd(sv, right_fd)) {
5333 errno = EBADF; /* as if it is closed */
5334 ash_msg_and_raise_error("%d: %m", right_fd);
5335 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005336 newfd = -1;
5337 } else {
5338 newfd = openredirect(redir); /* always >= 0 */
5339 if (fd == newfd) {
5340 /* Descriptor wasn't open before redirect.
5341 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005342 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005343 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005344 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005345 continue;
5346 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005347 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005348#if ENABLE_ASH_BASH_COMPAT
5349 redirect_more:
5350#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005351 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005352 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005353 /* Careful to not accidentally "save"
5354 * to the same fd as right side fd in N>&M */
5355 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5356 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005357/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5358 * are closed in popredir() in the child, preventing them from leaking
5359 * into child. (popredir() also cleans up the mess in case of failures)
5360 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005361 if (i == -1) {
5362 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005363 if (i != EBADF) {
5364 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005365 if (newfd >= 0)
5366 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005367 errno = i;
5368 ash_msg_and_raise_error("%d: %m", fd);
5369 /* NOTREACHED */
5370 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005371 /* EBADF: it is not open - good, remember to close it */
5372 remember_to_close:
5373 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005374 } else { /* fd is open, save its copy */
5375 /* "exec fd>&-" should not close fds
5376 * which point to script file(s).
5377 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005378 if (is_hidden_fd(sv, fd))
5379 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005380 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005381 if (fd == 2)
5382 copied_fd2 = i;
5383 sv->two_fd[sv_pos].orig = fd;
5384 sv->two_fd[sv_pos].copy = i;
5385 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005386 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005387 if (newfd < 0) {
5388 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005389 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005390 /* Don't want to trigger debugging */
5391 if (fd != -1)
5392 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005393 } else {
5394 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005395 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005396 } else if (fd != newfd) { /* move newfd to fd */
5397 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005398#if ENABLE_ASH_BASH_COMPAT
5399 if (!(redir->nfile.type == NTO2 && fd == 2))
5400#endif
5401 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005402 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005403#if ENABLE_ASH_BASH_COMPAT
5404 if (redir->nfile.type == NTO2 && fd == 1) {
5405 /* We already redirected it to fd 1, now copy it to 2 */
5406 newfd = 1;
5407 fd = 2;
5408 goto redirect_more;
5409 }
5410#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005411 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005412
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005413 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005414 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5415 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005416}
5417
5418/*
5419 * Undo the effects of the last redirection.
5420 */
5421static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005422popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005423{
5424 struct redirtab *rp;
5425 int i;
5426
Denis Vlasenko01631112007-12-16 17:20:38 +00005427 if (--g_nullredirs >= 0)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005428 return;
5429 INT_OFF;
5430 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005431 for (i = 0; i < rp->pair_count; i++) {
5432 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005433 int copy = rp->two_fd[i].copy;
5434 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005435 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005436 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005437 continue;
5438 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005439 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005440 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005441 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005442 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005443 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005444 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005445 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005446 }
5447 }
5448 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005449 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005450 free(rp);
5451 INT_ON;
5452}
5453
5454/*
5455 * Undo all redirections. Called on error or interrupt.
5456 */
5457
5458/*
5459 * Discard all saved file descriptors.
5460 */
5461static void
5462clearredir(int drop)
5463{
5464 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005465 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005466 if (!redirlist)
5467 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005468 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005469 }
5470}
5471
5472static int
5473redirectsafe(union node *redir, int flags)
5474{
5475 int err;
5476 volatile int saveint;
5477 struct jmploc *volatile savehandler = exception_handler;
5478 struct jmploc jmploc;
5479
5480 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005481 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5482 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005483 if (!err) {
5484 exception_handler = &jmploc;
5485 redirect(redir, flags);
5486 }
5487 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005488 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005489 longjmp(exception_handler->loc, 1);
5490 RESTORE_INT(saveint);
5491 return err;
5492}
5493
5494
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005495/* ============ Routines to expand arguments to commands
5496 *
5497 * We have to deal with backquotes, shell variables, and file metacharacters.
5498 */
5499
Mike Frysinger98c52642009-04-02 10:02:37 +00005500#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005501static arith_t
5502ash_arith(const char *s)
5503{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005504 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005505 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005506
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005507 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005508 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005509 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005510
5511 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005512 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005513 if (math_state.errmsg)
5514 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005515 INT_ON;
5516
5517 return result;
5518}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005519#endif
5520
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005521/*
5522 * expandarg flags
5523 */
5524#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5525#define EXP_TILDE 0x2 /* do normal tilde expansion */
5526#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5527#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5528#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5529#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5530#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5531#define EXP_WORD 0x80 /* expand word in parameter expansion */
5532#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5533/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005534 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005535 */
5536#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5537#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5538#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5539#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5540#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5541
5542/*
5543 * Structure specifying which parts of the string should be searched
5544 * for IFS characters.
5545 */
5546struct ifsregion {
5547 struct ifsregion *next; /* next region in list */
5548 int begoff; /* offset of start of region */
5549 int endoff; /* offset of end of region */
5550 int nulonly; /* search for nul bytes only */
5551};
5552
5553struct arglist {
5554 struct strlist *list;
5555 struct strlist **lastp;
5556};
5557
5558/* output of current string */
5559static char *expdest;
5560/* list of back quote expressions */
5561static struct nodelist *argbackq;
5562/* first struct in list of ifs regions */
5563static struct ifsregion ifsfirst;
5564/* last struct in list */
5565static struct ifsregion *ifslastp;
5566/* holds expanded arg list */
5567static struct arglist exparg;
5568
5569/*
5570 * Our own itoa().
5571 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005572#if !ENABLE_SH_MATH_SUPPORT
5573/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5574typedef long arith_t;
5575# define ARITH_FMT "%ld"
5576#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005577static int
5578cvtnum(arith_t num)
5579{
5580 int len;
5581
5582 expdest = makestrspace(32, expdest);
Denys Vlasenkobed7c812010-09-16 11:50:46 +02005583 len = fmtstr(expdest, 32, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005584 STADJUST(len, expdest);
5585 return len;
5586}
5587
5588static size_t
5589esclen(const char *start, const char *p)
5590{
5591 size_t esc = 0;
5592
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005593 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005594 esc++;
5595 }
5596 return esc;
5597}
5598
5599/*
5600 * Remove any CTLESC characters from a string.
5601 */
5602static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005603rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005604{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00005605 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005606
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005607 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005608 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005609 unsigned protect_against_glob;
5610 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005611
5612 p = strpbrk(str, qchars);
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005613 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005614 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005615
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005616 q = p;
5617 r = str;
5618 if (flag & RMESCAPE_ALLOC) {
5619 size_t len = p - str;
5620 size_t fulllen = len + strlen(p) + 1;
5621
5622 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005623 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005624 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005625 /* p and str may be invalidated by makestrspace */
5626 str = (char *)stackblock() + strloc;
5627 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005628 } else if (flag & RMESCAPE_HEAP) {
5629 r = ckmalloc(fulllen);
5630 } else {
5631 r = stalloc(fulllen);
5632 }
5633 q = r;
5634 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005635 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005636 }
5637 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005638
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005639 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5640 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005641 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005642 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005643 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005644// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5645// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5646// Note: both inquotes and protect_against_glob only affect whether
5647// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005648 inquotes = ~inquotes;
5649 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005650 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005651 continue;
5652 }
5653 if (*p == '\\') {
5654 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005655 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005656 goto copy;
5657 }
Denys Vlasenkocd716832009-11-28 22:14:02 +01005658 if ((unsigned char)*p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005659 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005660 if (protect_against_glob && inquotes && *p != '/') {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005661 *q++ = '\\';
5662 }
5663 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005664 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005665 copy:
5666 *q++ = *p++;
5667 }
5668 *q = '\0';
5669 if (flag & RMESCAPE_GROW) {
5670 expdest = r;
5671 STADJUST(q - r + 1, expdest);
5672 }
5673 return r;
5674}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005675#define pmatch(a, b) !fnmatch((a), (b), 0)
5676
5677/*
5678 * Prepare a pattern for a expmeta (internal glob(3)) call.
5679 *
5680 * Returns an stalloced string.
5681 */
5682static char *
5683preglob(const char *pattern, int quoted, int flag)
5684{
5685 flag |= RMESCAPE_GLOB;
5686 if (quoted) {
5687 flag |= RMESCAPE_QUOTED;
5688 }
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005689 return rmescapes((char *)pattern, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005690}
5691
5692/*
5693 * Put a string on the stack.
5694 */
5695static void
5696memtodest(const char *p, size_t len, int syntax, int quotes)
5697{
5698 char *q = expdest;
5699
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005700 q = makestrspace(quotes ? len * 2 : len, q);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005701
5702 while (len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005703 unsigned char c = *p++;
5704 if (c == '\0')
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005705 continue;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005706 if (quotes) {
5707 int n = SIT(c, syntax);
5708 if (n == CCTL || n == CBACK)
5709 USTPUTC(CTLESC, q);
5710 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005711 USTPUTC(c, q);
5712 }
5713
5714 expdest = q;
5715}
5716
5717static void
5718strtodest(const char *p, int syntax, int quotes)
5719{
5720 memtodest(p, strlen(p), syntax, quotes);
5721}
5722
5723/*
5724 * Record the fact that we have to scan this region of the
5725 * string for IFS characters.
5726 */
5727static void
5728recordregion(int start, int end, int nulonly)
5729{
5730 struct ifsregion *ifsp;
5731
5732 if (ifslastp == NULL) {
5733 ifsp = &ifsfirst;
5734 } else {
5735 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005736 ifsp = ckzalloc(sizeof(*ifsp));
5737 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005738 ifslastp->next = ifsp;
5739 INT_ON;
5740 }
5741 ifslastp = ifsp;
5742 ifslastp->begoff = start;
5743 ifslastp->endoff = end;
5744 ifslastp->nulonly = nulonly;
5745}
5746
5747static void
5748removerecordregions(int endoff)
5749{
5750 if (ifslastp == NULL)
5751 return;
5752
5753 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005754 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005755 struct ifsregion *ifsp;
5756 INT_OFF;
5757 ifsp = ifsfirst.next->next;
5758 free(ifsfirst.next);
5759 ifsfirst.next = ifsp;
5760 INT_ON;
5761 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005762 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005763 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005764 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005765 ifslastp = &ifsfirst;
5766 ifsfirst.endoff = endoff;
5767 }
5768 return;
5769 }
5770
5771 ifslastp = &ifsfirst;
5772 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005773 ifslastp = ifslastp->next;
5774 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005775 struct ifsregion *ifsp;
5776 INT_OFF;
5777 ifsp = ifslastp->next->next;
5778 free(ifslastp->next);
5779 ifslastp->next = ifsp;
5780 INT_ON;
5781 }
5782 if (ifslastp->endoff > endoff)
5783 ifslastp->endoff = endoff;
5784}
5785
5786static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005787exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005788{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005789 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005790 char *name;
5791 struct passwd *pw;
5792 const char *home;
Denys Vlasenko1166d7b2009-09-16 16:20:31 +02005793 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005794
5795 name = p + 1;
5796
5797 while ((c = *++p) != '\0') {
5798 switch (c) {
5799 case CTLESC:
5800 return startp;
5801 case CTLQUOTEMARK:
5802 return startp;
5803 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005804 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005805 goto done;
5806 break;
5807 case '/':
5808 case CTLENDVAR:
5809 goto done;
5810 }
5811 }
5812 done:
5813 *p = '\0';
5814 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005815 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005816 } else {
5817 pw = getpwnam(name);
5818 if (pw == NULL)
5819 goto lose;
5820 home = pw->pw_dir;
5821 }
5822 if (!home || !*home)
5823 goto lose;
5824 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005825 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005826 return p;
5827 lose:
5828 *p = c;
5829 return startp;
5830}
5831
5832/*
5833 * Execute a command inside back quotes. If it's a builtin command, we
5834 * want to save its output in a block obtained from malloc. Otherwise
5835 * we fork off a subprocess and get the output of the command via a pipe.
5836 * Should be called with interrupts off.
5837 */
5838struct backcmd { /* result of evalbackcmd */
5839 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005840 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005841 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005842 struct job *jp; /* job structure for command */
5843};
5844
5845/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005846static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005847#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02005848static void evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005849
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005850static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005851evalbackcmd(union node *n, struct backcmd *result)
5852{
5853 int saveherefd;
5854
5855 result->fd = -1;
5856 result->buf = NULL;
5857 result->nleft = 0;
5858 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005859 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005860 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005861
5862 saveherefd = herefd;
5863 herefd = -1;
5864
5865 {
5866 int pip[2];
5867 struct job *jp;
5868
5869 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005870 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005871 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005872 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5873 FORCE_INT_ON;
5874 close(pip[0]);
5875 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005876 /*close(1);*/
5877 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005878 close(pip[1]);
5879 }
5880 eflag = 0;
5881 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5882 /* NOTREACHED */
5883 }
5884 close(pip[1]);
5885 result->fd = pip[0];
5886 result->jp = jp;
5887 }
5888 herefd = saveherefd;
5889 out:
5890 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5891 result->fd, result->buf, result->nleft, result->jp));
5892}
5893
5894/*
5895 * Expand stuff in backwards quotes.
5896 */
5897static void
5898expbackq(union node *cmd, int quoted, int quotes)
5899{
5900 struct backcmd in;
5901 int i;
5902 char buf[128];
5903 char *p;
5904 char *dest;
5905 int startloc;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005906 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005907 struct stackmark smark;
5908
5909 INT_OFF;
5910 setstackmark(&smark);
5911 dest = expdest;
5912 startloc = dest - (char *)stackblock();
5913 grabstackstr(dest);
5914 evalbackcmd(cmd, &in);
5915 popstackmark(&smark);
5916
5917 p = in.buf;
5918 i = in.nleft;
5919 if (i == 0)
5920 goto read;
5921 for (;;) {
5922 memtodest(p, i, syntax, quotes);
5923 read:
5924 if (in.fd < 0)
5925 break;
Denys Vlasenko80542ba2011-05-08 21:23:43 +02005926 i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005927 TRACE(("expbackq: read returns %d\n", i));
5928 if (i <= 0)
5929 break;
5930 p = buf;
5931 }
5932
Denis Vlasenko60818682007-09-28 22:07:23 +00005933 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005934 if (in.fd >= 0) {
5935 close(in.fd);
5936 back_exitstatus = waitforjob(in.jp);
5937 }
5938 INT_ON;
5939
5940 /* Eat all trailing newlines */
5941 dest = expdest;
5942 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5943 STUNPUTC(dest);
5944 expdest = dest;
5945
5946 if (quoted == 0)
5947 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005948 TRACE(("evalbackq: size:%d:'%.*s'\n",
5949 (int)((dest - (char *)stackblock()) - startloc),
5950 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005951 stackblock() + startloc));
5952}
5953
Mike Frysinger98c52642009-04-02 10:02:37 +00005954#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005955/*
5956 * Expand arithmetic expression. Backup to start of expression,
5957 * evaluate, place result in (backed up) result, adjust string position.
5958 */
5959static void
5960expari(int quotes)
5961{
5962 char *p, *start;
5963 int begoff;
5964 int flag;
5965 int len;
5966
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005967 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005968
5969 /*
5970 * This routine is slightly over-complicated for
5971 * efficiency. Next we scan backwards looking for the
5972 * start of arithmetic.
5973 */
5974 start = stackblock();
5975 p = expdest - 1;
5976 *p = '\0';
5977 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005978 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005979 int esc;
5980
Denys Vlasenkocd716832009-11-28 22:14:02 +01005981 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005982 p--;
5983#if DEBUG
5984 if (p < start) {
5985 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5986 }
5987#endif
5988 }
5989
5990 esc = esclen(start, p);
5991 if (!(esc % 2)) {
5992 break;
5993 }
5994
5995 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005996 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005997
5998 begoff = p - start;
5999
6000 removerecordregions(begoff);
6001
6002 flag = p[1];
6003
6004 expdest = p;
6005
6006 if (quotes)
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006007 rmescapes(p + 2, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006008
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00006009 len = cvtnum(ash_arith(p + 2));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006010
6011 if (flag != '"')
6012 recordregion(begoff, begoff + len, 0);
6013}
6014#endif
6015
6016/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006017static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006018
6019/*
6020 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6021 * characters to allow for further processing. Otherwise treat
6022 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006023 *
6024 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6025 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6026 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006027 */
6028static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006029argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006030{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006031 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006032 '=',
6033 ':',
6034 CTLQUOTEMARK,
6035 CTLENDVAR,
6036 CTLESC,
6037 CTLVAR,
6038 CTLBACKQ,
6039 CTLBACKQ | CTLQUOTE,
Mike Frysinger98c52642009-04-02 10:02:37 +00006040#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006041 CTLENDARI,
6042#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006043 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006044 };
6045 const char *reject = spclchars;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006046 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
6047 int breakall = flags & EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006048 int inquotes;
6049 size_t length;
6050 int startloc;
6051
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006052 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006053 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006054 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006055 reject++;
6056 }
6057 inquotes = 0;
6058 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006059 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006060 char *q;
6061
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006062 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006063 tilde:
6064 q = p;
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006065 if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006066 q++;
6067 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006068 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069 }
6070 start:
6071 startloc = expdest - (char *)stackblock();
6072 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006073 unsigned char c;
6074
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006075 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006076 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006077 if (c) {
6078 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006079 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006080 ) {
6081 /* c == '=' || c == ':' || c == CTLENDARI */
6082 length++;
6083 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006084 }
6085 if (length > 0) {
6086 int newloc;
6087 expdest = stack_nputstr(p, length, expdest);
6088 newloc = expdest - (char *)stackblock();
6089 if (breakall && !inquotes && newloc > startloc) {
6090 recordregion(startloc, newloc, 0);
6091 }
6092 startloc = newloc;
6093 }
6094 p += length + 1;
6095 length = 0;
6096
6097 switch (c) {
6098 case '\0':
6099 goto breakloop;
6100 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006101 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006102 p--;
6103 continue;
6104 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006105 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006106 reject++;
6107 /* fall through */
6108 case ':':
6109 /*
6110 * sort of a hack - expand tildes in variable
6111 * assignments (after the first '=' and after ':'s).
6112 */
6113 if (*--p == '~') {
6114 goto tilde;
6115 }
6116 continue;
6117 }
6118
6119 switch (c) {
6120 case CTLENDVAR: /* ??? */
6121 goto breakloop;
6122 case CTLQUOTEMARK:
6123 /* "$@" syntax adherence hack */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006124 if (!inquotes
6125 && memcmp(p, dolatstr, 4) == 0
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006126 && ( p[4] == (char)CTLQUOTEMARK
6127 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006128 )
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006129 ) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006130 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006131 goto start;
6132 }
6133 inquotes = !inquotes;
6134 addquote:
6135 if (quotes) {
6136 p--;
6137 length++;
6138 startloc++;
6139 }
6140 break;
6141 case CTLESC:
6142 startloc++;
6143 length++;
6144 goto addquote;
6145 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006146 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006147 p = evalvar(p, flags, 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:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006151 c = '\0';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006152 case CTLBACKQ|CTLQUOTE:
6153 expbackq(argbackq->n, c, quotes);
6154 argbackq = argbackq->next;
6155 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006156#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006157 case CTLENDARI:
6158 p--;
6159 expari(quotes);
6160 goto start;
6161#endif
6162 }
6163 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006164 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006165}
6166
6167static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006168scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6169 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006170{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006171 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006172 char c;
6173
6174 loc = startp;
6175 loc2 = rmesc;
6176 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006177 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006178 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006179
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006180 c = *loc2;
6181 if (zero) {
6182 *loc2 = '\0';
6183 s = rmesc;
6184 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006185 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006186
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006187 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006188 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006189 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006190 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006191 loc++;
6192 loc++;
6193 loc2++;
6194 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006195 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006196}
6197
6198static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006199scanright(char *startp, char *rmesc, char *rmescend,
6200 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006201{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006202#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6203 int try2optimize = match_at_start;
6204#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006205 int esc = 0;
6206 char *loc;
6207 char *loc2;
6208
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006209 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6210 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6211 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6212 * Logic:
6213 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6214 * and on each iteration they go back two/one char until they reach the beginning.
6215 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6216 */
6217 /* TODO: document in what other circumstances we are called. */
6218
6219 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006220 int match;
6221 char c = *loc2;
6222 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006223 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006224 *loc2 = '\0';
6225 s = rmesc;
6226 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006227 match = pmatch(pattern, s);
6228 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006229 *loc2 = c;
6230 if (match)
6231 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006232#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6233 if (try2optimize) {
6234 /* Maybe we can optimize this:
6235 * if pattern ends with unescaped *, we can avoid checking
6236 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6237 * it wont match truncated "raw_value_of_" strings too.
6238 */
6239 unsigned plen = strlen(pattern);
6240 /* Does it end with "*"? */
6241 if (plen != 0 && pattern[--plen] == '*') {
6242 /* "xxxx*" is not escaped */
6243 /* "xxx\*" is escaped */
6244 /* "xx\\*" is not escaped */
6245 /* "x\\\*" is escaped */
6246 int slashes = 0;
6247 while (plen != 0 && pattern[--plen] == '\\')
6248 slashes++;
6249 if (!(slashes & 1))
6250 break; /* ends with unescaped "*" */
6251 }
6252 try2optimize = 0;
6253 }
6254#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006255 loc--;
6256 if (quotes) {
6257 if (--esc < 0) {
6258 esc = esclen(startp, loc);
6259 }
6260 if (esc % 2) {
6261 esc--;
6262 loc--;
6263 }
6264 }
6265 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006266 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006267}
6268
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006269static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270static void
6271varunset(const char *end, const char *var, const char *umsg, int varflags)
6272{
6273 const char *msg;
6274 const char *tail;
6275
6276 tail = nullstr;
6277 msg = "parameter not set";
6278 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006279 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006280 if (varflags & VSNUL)
6281 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006282 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006283 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006284 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006285 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006286 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006287}
6288
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006289#if ENABLE_ASH_BASH_COMPAT
6290static char *
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006291parse_sub_pattern(char *arg, int varflags)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006292{
6293 char *idx, *repl = NULL;
6294 unsigned char c;
6295
Denys Vlasenko16149002010-08-06 22:06:21 +02006296 //char *org_arg = arg;
Denys Vlasenko33bbb272010-08-07 22:24:36 +02006297 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags);
Denis Vlasenko2659c632008-06-14 06:04:59 +00006298 idx = arg;
6299 while (1) {
6300 c = *arg;
6301 if (!c)
6302 break;
6303 if (c == '/') {
6304 /* Only the first '/' seen is our separator */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006305 if (!repl) {
Denis Vlasenko2659c632008-06-14 06:04:59 +00006306 repl = idx + 1;
6307 c = '\0';
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006308 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006309 }
Denis Vlasenko2659c632008-06-14 06:04:59 +00006310 *idx++ = c;
Denis Vlasenko2659c632008-06-14 06:04:59 +00006311 arg++;
Denys Vlasenko33bbb272010-08-07 22:24:36 +02006312 /*
6313 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_}
6314 * The result is a_\_z_c (not a\_\_z_c)!
6315 *
6316 * Enable debug prints in this function and you'll see:
6317 * ash: arg:'\\b/_\\_z_' varflags:d
6318 * ash: pattern:'\\b' repl:'_\_z_'
6319 * That is, \\b is interpreted as \\b, but \\_ as \_!
6320 * IOW: search pattern and replace string treat backslashes
6321 * differently! That is the reason why we check repl below:
6322 */
6323 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE))
6324 arg++; /* skip both '\', not just first one */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006325 }
Denis Vlasenko29038c02008-06-14 06:14:02 +00006326 *idx = c; /* NUL */
Denys Vlasenko16149002010-08-06 22:06:21 +02006327 //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006328
6329 return repl;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006330}
6331#endif /* ENABLE_ASH_BASH_COMPAT */
6332
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006333static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006334subevalvar(char *p, char *varname, int strloc, int subtype,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006335 int startloc, int varflags, int quotes, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006336{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006337 struct nodelist *saveargbackq = argbackq;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006338 char *startp;
6339 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006340 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006341 char *str;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006342 IF_ASH_BASH_COMPAT(const char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006343 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006344 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006345 int amount, resetloc;
6346 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006347 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006348 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006349
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006350 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6351 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006352
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006353 herefd = -1;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006354 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6355 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006356 STPUTC('\0', expdest);
6357 herefd = saveherefd;
6358 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006359 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006360
6361 switch (subtype) {
6362 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006363 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006364 amount = startp - expdest;
6365 STADJUST(amount, expdest);
6366 return startp;
6367
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006368 case VSQUESTION:
6369 varunset(p, varname, startp, varflags);
6370 /* NOTREACHED */
6371
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006372#if ENABLE_ASH_BASH_COMPAT
6373 case VSSUBSTR:
6374 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006375 /* Read POS in ${var:POS:LEN} */
6376 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006377 len = str - startp - 1;
6378
6379 /* *loc != '\0', guaranteed by parser */
6380 if (quotes) {
6381 char *ptr;
6382
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006383 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006384 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006385 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006386 len--;
6387 ptr++;
6388 }
6389 }
6390 }
6391 orig_len = len;
6392
6393 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006394 /* ${var::LEN} */
6395 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006396 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006397 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006398 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006399 while (*loc && *loc != ':') {
6400 /* TODO?
6401 * bash complains on: var=qwe; echo ${var:1a:123}
6402 if (!isdigit(*loc))
6403 ash_msg_and_raise_error(msg_illnum, str);
6404 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006405 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006406 }
6407 if (*loc++ == ':') {
6408 len = number(loc);
6409 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006410 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006411 if (pos < 0) {
6412 /* ${VAR:$((-n)):l} starts n chars from the end */
6413 pos = orig_len + pos;
6414 }
6415 if ((unsigned)pos >= orig_len) {
6416 /* apart from obvious ${VAR:999999:l},
6417 * covers ${VAR:$((-9999999)):l} - result is ""
6418 * (bash-compat)
6419 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006420 pos = 0;
6421 len = 0;
6422 }
6423 if (len > (orig_len - pos))
6424 len = orig_len - pos;
6425
6426 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006427 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006428 str++;
6429 }
6430 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006431 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006432 *loc++ = *str++;
6433 *loc++ = *str++;
6434 }
6435 *loc = '\0';
6436 amount = loc - expdest;
6437 STADJUST(amount, expdest);
6438 return loc;
6439#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006440 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006441
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006442 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006443
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006444 /* We'll comeback here if we grow the stack while handling
6445 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6446 * stack will need rebasing, and we'll need to remove our work
6447 * areas each time
6448 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006449 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006450
6451 amount = expdest - ((char *)stackblock() + resetloc);
6452 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006453 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006454
6455 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006456 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006457 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006458 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006459 if (rmesc != startp) {
6460 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006461 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006462 }
6463 }
6464 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006465 str = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006466 preglob(str, varflags & VSQUOTE, 0);
6467
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006468#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006469 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006470 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006471 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006472
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006473 if (!repl) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006474 repl = parse_sub_pattern(str, varflags);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006475 //bb_error_msg("repl:'%s'", repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006476 if (!repl)
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006477 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006478 }
6479
6480 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006481 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006482 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006483
6484 len = 0;
6485 idx = startp;
6486 end = str - 1;
6487 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006488 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006489 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006490 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006491 if (!loc) {
6492 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006493 char *restart_detect = stackblock();
6494 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006495 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006496 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006497 idx++;
6498 len++;
6499 STPUTC(*idx, expdest);
6500 }
6501 if (stackblock() != restart_detect)
6502 goto restart;
6503 idx++;
6504 len++;
6505 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006506 /* continue; - prone to quadratic behavior, smarter code: */
6507 if (idx >= end)
6508 break;
6509 if (str[0] == '*') {
6510 /* Pattern is "*foo". If "*foo" does not match "long_string",
6511 * it would never match "ong_string" etc, no point in trying.
6512 */
6513 goto skip_matching;
6514 }
6515 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006516 }
6517
6518 if (subtype == VSREPLACEALL) {
6519 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006520 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006521 idx++;
6522 idx++;
6523 rmesc++;
6524 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006525 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006526 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006527 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006528
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006529 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006530 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006531 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006532 if (quotes && *loc == '\\') {
6533 STPUTC(CTLESC, expdest);
6534 len++;
6535 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006536 STPUTC(*loc, expdest);
6537 if (stackblock() != restart_detect)
6538 goto restart;
6539 len++;
6540 }
6541
6542 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006543 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006544 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006545 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006546 STPUTC(*idx, expdest);
6547 if (stackblock() != restart_detect)
6548 goto restart;
6549 len++;
6550 idx++;
6551 }
6552 break;
6553 }
6554 }
6555
6556 /* We've put the replaced text into a buffer at workloc, now
6557 * move it to the right place and adjust the stack.
6558 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006559 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006560 startp = (char *)stackblock() + startloc;
6561 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006562 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006563 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006564 STADJUST(-amount, expdest);
6565 return startp;
6566 }
6567#endif /* ENABLE_ASH_BASH_COMPAT */
6568
6569 subtype -= VSTRIMRIGHT;
6570#if DEBUG
6571 if (subtype < 0 || subtype > 7)
6572 abort();
6573#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006574 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006575 zero = subtype >> 1;
6576 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6577 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6578
6579 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6580 if (loc) {
6581 if (zero) {
6582 memmove(startp, loc, str - loc);
6583 loc = startp + (str - loc) - 1;
6584 }
6585 *loc = '\0';
6586 amount = loc - expdest;
6587 STADJUST(amount, expdest);
6588 }
6589 return loc;
6590}
6591
6592/*
6593 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006594 * name parameter (examples):
6595 * ash -c 'echo $1' name:'1='
6596 * ash -c 'echo $qwe' name:'qwe='
6597 * ash -c 'echo $$' name:'$='
6598 * ash -c 'echo ${$}' name:'$='
6599 * ash -c 'echo ${$##q}' name:'$=q'
6600 * ash -c 'echo ${#$}' name:'$='
6601 * note: examples with bad shell syntax:
6602 * ash -c 'echo ${#$1}' name:'$=1'
6603 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006604 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006605static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006606varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607{
Mike Frysinger98c52642009-04-02 10:02:37 +00006608 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006609 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006610 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006611 int sepq = 0;
6612 ssize_t len = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006613 int subtype = varflags & VSTYPE;
Denys Vlasenko1166d7b2009-09-16 16:20:31 +02006614 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006615 int quoted = varflags & VSQUOTE;
6616 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006617
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006618 switch (*name) {
6619 case '$':
6620 num = rootpid;
6621 goto numvar;
6622 case '?':
6623 num = exitstatus;
6624 goto numvar;
6625 case '#':
6626 num = shellparam.nparam;
6627 goto numvar;
6628 case '!':
6629 num = backgndpid;
6630 if (num == 0)
6631 return -1;
6632 numvar:
6633 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006634 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006635 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006636 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006637 for (i = NOPTS - 1; i >= 0; i--) {
6638 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006639 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006640 len++;
6641 }
6642 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006643 check_1char_name:
6644#if 0
6645 /* handles cases similar to ${#$1} */
6646 if (name[2] != '\0')
6647 raise_error_syntax("bad substitution");
6648#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006649 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006650 case '@': {
6651 char **ap;
6652 int sep;
6653
6654 if (quoted && (flags & EXP_FULL)) {
6655 /* note: this is not meant as PEOF value */
6656 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006657 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006658 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006659 /* fall through */
6660 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006661 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006662 i = SIT(sep, syntax);
6663 if (quotes && (i == CCTL || i == CBACK))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006664 sepq = 1;
6665 param:
6666 ap = shellparam.p;
6667 if (!ap)
6668 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006669 while ((p = *ap++) != NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006670 size_t partlen;
6671
6672 partlen = strlen(p);
6673 len += partlen;
6674
6675 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6676 memtodest(p, partlen, syntax, quotes);
6677
6678 if (*ap && sep) {
6679 char *q;
6680
6681 len++;
6682 if (subtype == VSPLUS || subtype == VSLENGTH) {
6683 continue;
6684 }
6685 q = expdest;
6686 if (sepq)
6687 STPUTC(CTLESC, q);
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006688 /* note: may put NUL despite sep != 0
6689 * (see sep = 1 << CHAR_BIT above) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006690 STPUTC(sep, q);
6691 expdest = q;
6692 }
6693 }
6694 return len;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006695 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006696 case '0':
6697 case '1':
6698 case '2':
6699 case '3':
6700 case '4':
6701 case '5':
6702 case '6':
6703 case '7':
6704 case '8':
6705 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006706 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006707 if (num < 0 || num > shellparam.nparam)
6708 return -1;
6709 p = num ? shellparam.p[num - 1] : arg0;
6710 goto value;
6711 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006712 /* NB: name has form "VAR=..." */
6713
6714 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6715 * which should be considered before we check variables. */
6716 if (var_str_list) {
6717 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6718 p = NULL;
6719 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006720 char *str, *eq;
6721 str = var_str_list->text;
6722 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006723 if (!eq) /* stop at first non-assignment */
6724 break;
6725 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006726 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006727 && strncmp(str, name, name_len) == 0
6728 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006729 p = eq;
6730 /* goto value; - WRONG! */
6731 /* think "A=1 A=2 B=$A" */
6732 }
6733 var_str_list = var_str_list->next;
6734 } while (var_str_list);
6735 if (p)
6736 goto value;
6737 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006738 p = lookupvar(name);
6739 value:
6740 if (!p)
6741 return -1;
6742
6743 len = strlen(p);
6744 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6745 memtodest(p, len, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006746#if ENABLE_UNICODE_SUPPORT
6747 if (subtype == VSLENGTH && len > 0) {
6748 reinit_unicode_for_ash();
6749 if (unicode_status == UNICODE_ON) {
6750 len = unicode_strlen(p);
6751 }
6752 }
6753#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006754 return len;
6755 }
6756
6757 if (subtype == VSPLUS || subtype == VSLENGTH)
6758 STADJUST(-len, expdest);
6759 return len;
6760}
6761
6762/*
6763 * Expand a variable, and return a pointer to the next character in the
6764 * input string.
6765 */
6766static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006767evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006768{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006769 char varflags;
6770 char subtype;
6771 char quoted;
6772 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006773 char *var;
6774 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006775 int startloc;
6776 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006777
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006778 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006779 subtype = varflags & VSTYPE;
6780 quoted = varflags & VSQUOTE;
6781 var = p;
6782 easy = (!quoted || (*var == '@' && shellparam.nparam));
6783 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006784 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006785
6786 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006787 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006788 if (varflags & VSNUL)
6789 varlen--;
6790
6791 if (subtype == VSPLUS) {
6792 varlen = -1 - varlen;
6793 goto vsplus;
6794 }
6795
6796 if (subtype == VSMINUS) {
6797 vsplus:
6798 if (varlen < 0) {
6799 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006800 p,
6801 flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD),
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006802 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006803 );
6804 goto end;
6805 }
6806 if (easy)
6807 goto record;
6808 goto end;
6809 }
6810
6811 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6812 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006813 if (subevalvar(p, var, /* strloc: */ 0,
6814 subtype, startloc, varflags,
6815 /* quotes: */ 0,
6816 var_str_list)
6817 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006818 varflags &= ~VSNUL;
6819 /*
6820 * Remove any recorded regions beyond
6821 * start of variable
6822 */
6823 removerecordregions(startloc);
6824 goto again;
6825 }
6826 goto end;
6827 }
6828 if (easy)
6829 goto record;
6830 goto end;
6831 }
6832
6833 if (varlen < 0 && uflag)
6834 varunset(p, var, 0, 0);
6835
6836 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006837 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006838 goto record;
6839 }
6840
6841 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006842 if (easy)
6843 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006844 goto end;
6845 }
6846
6847#if DEBUG
6848 switch (subtype) {
6849 case VSTRIMLEFT:
6850 case VSTRIMLEFTMAX:
6851 case VSTRIMRIGHT:
6852 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006853#if ENABLE_ASH_BASH_COMPAT
6854 case VSSUBSTR:
6855 case VSREPLACE:
6856 case VSREPLACEALL:
6857#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006858 break;
6859 default:
6860 abort();
6861 }
6862#endif
6863
6864 if (varlen >= 0) {
6865 /*
6866 * Terminate the string and start recording the pattern
6867 * right after it
6868 */
6869 STPUTC('\0', expdest);
6870 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006871 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006872 startloc, varflags,
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006873 /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR),
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006874 var_str_list)
6875 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006876 int amount = expdest - (
6877 (char *)stackblock() + patloc - 1
6878 );
6879 STADJUST(-amount, expdest);
6880 }
6881 /* Remove any recorded regions beyond start of variable */
6882 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006883 record:
6884 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006885 }
6886
6887 end:
6888 if (subtype != VSNORMAL) { /* skip to end of alternative */
6889 int nesting = 1;
6890 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006891 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006892 if (c == CTLESC)
6893 p++;
6894 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6895 if (varlen >= 0)
6896 argbackq = argbackq->next;
6897 } else if (c == CTLVAR) {
6898 if ((*p++ & VSTYPE) != VSNORMAL)
6899 nesting++;
6900 } else if (c == CTLENDVAR) {
6901 if (--nesting == 0)
6902 break;
6903 }
6904 }
6905 }
6906 return p;
6907}
6908
6909/*
6910 * Break the argument string into pieces based upon IFS and add the
6911 * strings to the argument list. The regions of the string to be
6912 * searched for IFS characters have been stored by recordregion.
6913 */
6914static void
6915ifsbreakup(char *string, struct arglist *arglist)
6916{
6917 struct ifsregion *ifsp;
6918 struct strlist *sp;
6919 char *start;
6920 char *p;
6921 char *q;
6922 const char *ifs, *realifs;
6923 int ifsspc;
6924 int nulonly;
6925
6926 start = string;
6927 if (ifslastp != NULL) {
6928 ifsspc = 0;
6929 nulonly = 0;
6930 realifs = ifsset() ? ifsval() : defifs;
6931 ifsp = &ifsfirst;
6932 do {
6933 p = string + ifsp->begoff;
6934 nulonly = ifsp->nulonly;
6935 ifs = nulonly ? nullstr : realifs;
6936 ifsspc = 0;
6937 while (p < string + ifsp->endoff) {
6938 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006939 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006940 p++;
6941 if (!strchr(ifs, *p)) {
6942 p++;
6943 continue;
6944 }
6945 if (!nulonly)
6946 ifsspc = (strchr(defifs, *p) != NULL);
6947 /* Ignore IFS whitespace at start */
6948 if (q == start && ifsspc) {
6949 p++;
6950 start = p;
6951 continue;
6952 }
6953 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006954 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006955 sp->text = start;
6956 *arglist->lastp = sp;
6957 arglist->lastp = &sp->next;
6958 p++;
6959 if (!nulonly) {
6960 for (;;) {
6961 if (p >= string + ifsp->endoff) {
6962 break;
6963 }
6964 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006965 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006966 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006967 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006968 p = q;
6969 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006970 }
6971 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006972 if (ifsspc) {
6973 p++;
6974 ifsspc = 0;
6975 } else {
6976 p = q;
6977 break;
6978 }
6979 } else
6980 p++;
6981 }
6982 }
6983 start = p;
6984 } /* while */
6985 ifsp = ifsp->next;
6986 } while (ifsp != NULL);
6987 if (nulonly)
6988 goto add;
6989 }
6990
6991 if (!*start)
6992 return;
6993
6994 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006995 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006996 sp->text = start;
6997 *arglist->lastp = sp;
6998 arglist->lastp = &sp->next;
6999}
7000
7001static void
7002ifsfree(void)
7003{
7004 struct ifsregion *p;
7005
7006 INT_OFF;
7007 p = ifsfirst.next;
7008 do {
7009 struct ifsregion *ifsp;
7010 ifsp = p->next;
7011 free(p);
7012 p = ifsp;
7013 } while (p);
7014 ifslastp = NULL;
7015 ifsfirst.next = NULL;
7016 INT_ON;
7017}
7018
7019/*
7020 * Add a file name to the list.
7021 */
7022static void
7023addfname(const char *name)
7024{
7025 struct strlist *sp;
7026
Denis Vlasenko597906c2008-02-20 16:38:54 +00007027 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007028 sp->text = ststrdup(name);
7029 *exparg.lastp = sp;
7030 exparg.lastp = &sp->next;
7031}
7032
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007033/*
7034 * Do metacharacter (i.e. *, ?, [...]) expansion.
7035 */
7036static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007037expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007038{
7039 char *p;
7040 const char *cp;
7041 char *start;
7042 char *endname;
7043 int metaflag;
7044 struct stat statb;
7045 DIR *dirp;
7046 struct dirent *dp;
7047 int atend;
7048 int matchdot;
7049
7050 metaflag = 0;
7051 start = name;
7052 for (p = name; *p; p++) {
7053 if (*p == '*' || *p == '?')
7054 metaflag = 1;
7055 else if (*p == '[') {
7056 char *q = p + 1;
7057 if (*q == '!')
7058 q++;
7059 for (;;) {
7060 if (*q == '\\')
7061 q++;
7062 if (*q == '/' || *q == '\0')
7063 break;
7064 if (*++q == ']') {
7065 metaflag = 1;
7066 break;
7067 }
7068 }
7069 } else if (*p == '\\')
7070 p++;
7071 else if (*p == '/') {
7072 if (metaflag)
7073 goto out;
7074 start = p + 1;
7075 }
7076 }
7077 out:
7078 if (metaflag == 0) { /* we've reached the end of the file name */
7079 if (enddir != expdir)
7080 metaflag++;
7081 p = name;
7082 do {
7083 if (*p == '\\')
7084 p++;
7085 *enddir++ = *p;
7086 } while (*p++);
7087 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7088 addfname(expdir);
7089 return;
7090 }
7091 endname = p;
7092 if (name < start) {
7093 p = name;
7094 do {
7095 if (*p == '\\')
7096 p++;
7097 *enddir++ = *p++;
7098 } while (p < start);
7099 }
7100 if (enddir == expdir) {
7101 cp = ".";
7102 } else if (enddir == expdir + 1 && *expdir == '/') {
7103 cp = "/";
7104 } else {
7105 cp = expdir;
7106 enddir[-1] = '\0';
7107 }
7108 dirp = opendir(cp);
7109 if (dirp == NULL)
7110 return;
7111 if (enddir != expdir)
7112 enddir[-1] = '/';
7113 if (*endname == 0) {
7114 atend = 1;
7115 } else {
7116 atend = 0;
7117 *endname++ = '\0';
7118 }
7119 matchdot = 0;
7120 p = start;
7121 if (*p == '\\')
7122 p++;
7123 if (*p == '.')
7124 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007125 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007126 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007127 continue;
7128 if (pmatch(start, dp->d_name)) {
7129 if (atend) {
7130 strcpy(enddir, dp->d_name);
7131 addfname(expdir);
7132 } else {
7133 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7134 continue;
7135 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007136 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007137 }
7138 }
7139 }
7140 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007141 if (!atend)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007142 endname[-1] = '/';
7143}
7144
7145static struct strlist *
7146msort(struct strlist *list, int len)
7147{
7148 struct strlist *p, *q = NULL;
7149 struct strlist **lpp;
7150 int half;
7151 int n;
7152
7153 if (len <= 1)
7154 return list;
7155 half = len >> 1;
7156 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007157 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007158 q = p;
7159 p = p->next;
7160 }
7161 q->next = NULL; /* terminate first half of list */
7162 q = msort(list, half); /* sort first half of list */
7163 p = msort(p, len - half); /* sort second half */
7164 lpp = &list;
7165 for (;;) {
7166#if ENABLE_LOCALE_SUPPORT
7167 if (strcoll(p->text, q->text) < 0)
7168#else
7169 if (strcmp(p->text, q->text) < 0)
7170#endif
7171 {
7172 *lpp = p;
7173 lpp = &p->next;
7174 p = *lpp;
7175 if (p == NULL) {
7176 *lpp = q;
7177 break;
7178 }
7179 } else {
7180 *lpp = q;
7181 lpp = &q->next;
7182 q = *lpp;
7183 if (q == NULL) {
7184 *lpp = p;
7185 break;
7186 }
7187 }
7188 }
7189 return list;
7190}
7191
7192/*
7193 * Sort the results of file name expansion. It calculates the number of
7194 * strings to sort and then calls msort (short for merge sort) to do the
7195 * work.
7196 */
7197static struct strlist *
7198expsort(struct strlist *str)
7199{
7200 int len;
7201 struct strlist *sp;
7202
7203 len = 0;
7204 for (sp = str; sp; sp = sp->next)
7205 len++;
7206 return msort(str, len);
7207}
7208
7209static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007210expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007211{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007212 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007213 '*', '?', '[', 0
7214 };
7215 /* TODO - EXP_REDIR */
7216
7217 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007218 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007219 struct strlist **savelastp;
7220 struct strlist *sp;
7221 char *p;
7222
7223 if (fflag)
7224 goto nometa;
7225 if (!strpbrk(str->text, metachars))
7226 goto nometa;
7227 savelastp = exparg.lastp;
7228
7229 INT_OFF;
7230 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7231 {
7232 int i = strlen(str->text);
7233 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7234 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007235 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007236 free(expdir);
7237 if (p != str->text)
7238 free(p);
7239 INT_ON;
7240 if (exparg.lastp == savelastp) {
7241 /*
7242 * no matches
7243 */
7244 nometa:
7245 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007246 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007247 exparg.lastp = &str->next;
7248 } else {
7249 *exparg.lastp = NULL;
7250 *savelastp = sp = expsort(*savelastp);
7251 while (sp->next != NULL)
7252 sp = sp->next;
7253 exparg.lastp = &sp->next;
7254 }
7255 str = str->next;
7256 }
7257}
7258
7259/*
7260 * Perform variable substitution and command substitution on an argument,
7261 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7262 * perform splitting and file name expansion. When arglist is NULL, perform
7263 * here document expansion.
7264 */
7265static void
7266expandarg(union node *arg, struct arglist *arglist, int flag)
7267{
7268 struct strlist *sp;
7269 char *p;
7270
7271 argbackq = arg->narg.backquote;
7272 STARTSTACKSTR(expdest);
7273 ifsfirst.next = NULL;
7274 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007275 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007276 argstr(arg->narg.text, flag,
7277 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007278 p = _STPUTC('\0', expdest);
7279 expdest = p - 1;
7280 if (arglist == NULL) {
7281 return; /* here document expanded */
7282 }
7283 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007284 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007285 exparg.lastp = &exparg.list;
7286 /*
7287 * TODO - EXP_REDIR
7288 */
7289 if (flag & EXP_FULL) {
7290 ifsbreakup(p, &exparg);
7291 *exparg.lastp = NULL;
7292 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007293 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007294 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007295 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007296 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007297 TRACE(("expandarg: rmescapes:'%s'\n", p));
7298 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007299 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007300 sp->text = p;
7301 *exparg.lastp = sp;
7302 exparg.lastp = &sp->next;
7303 }
7304 if (ifsfirst.next)
7305 ifsfree();
7306 *exparg.lastp = NULL;
7307 if (exparg.list) {
7308 *arglist->lastp = exparg.list;
7309 arglist->lastp = exparg.lastp;
7310 }
7311}
7312
7313/*
7314 * Expand shell variables and backquotes inside a here document.
7315 */
7316static void
7317expandhere(union node *arg, int fd)
7318{
7319 herefd = fd;
7320 expandarg(arg, (struct arglist *)NULL, 0);
7321 full_write(fd, stackblock(), expdest - (char *)stackblock());
7322}
7323
7324/*
7325 * Returns true if the pattern matches the string.
7326 */
7327static int
7328patmatch(char *pattern, const char *string)
7329{
7330 return pmatch(preglob(pattern, 0, 0), string);
7331}
7332
7333/*
7334 * See if a pattern matches in a case statement.
7335 */
7336static int
7337casematch(union node *pattern, char *val)
7338{
7339 struct stackmark smark;
7340 int result;
7341
7342 setstackmark(&smark);
7343 argbackq = pattern->narg.backquote;
7344 STARTSTACKSTR(expdest);
7345 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007346 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7347 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007348 STACKSTRNUL(expdest);
7349 result = patmatch(stackblock(), val);
7350 popstackmark(&smark);
7351 return result;
7352}
7353
7354
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007355/* ============ find_command */
7356
7357struct builtincmd {
7358 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007359 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007360 /* unsigned flags; */
7361};
7362#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007363/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007364 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007365#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007366#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007367
7368struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007369 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007370 union param {
7371 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007372 /* index >= 0 for commands without path (slashes) */
7373 /* (TODO: what exactly does the value mean? PATH position?) */
7374 /* index == -1 for commands with slashes */
7375 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007376 const struct builtincmd *cmd;
7377 struct funcnode *func;
7378 } u;
7379};
7380/* values of cmdtype */
7381#define CMDUNKNOWN -1 /* no entry in table for command */
7382#define CMDNORMAL 0 /* command is an executable program */
7383#define CMDFUNCTION 1 /* command is a shell function */
7384#define CMDBUILTIN 2 /* command is a shell builtin */
7385
7386/* action to find_command() */
7387#define DO_ERR 0x01 /* prints errors */
7388#define DO_ABS 0x02 /* checks absolute paths */
7389#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7390#define DO_ALTPATH 0x08 /* using alternate path */
7391#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7392
7393static void find_command(char *, struct cmdentry *, int, const char *);
7394
7395
7396/* ============ Hashing commands */
7397
7398/*
7399 * When commands are first encountered, they are entered in a hash table.
7400 * This ensures that a full path search will not have to be done for them
7401 * on each invocation.
7402 *
7403 * We should investigate converting to a linear search, even though that
7404 * would make the command name "hash" a misnomer.
7405 */
7406
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007407struct tblentry {
7408 struct tblentry *next; /* next entry in hash chain */
7409 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007410 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007411 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007412 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007413};
7414
Denis Vlasenko01631112007-12-16 17:20:38 +00007415static struct tblentry **cmdtable;
7416#define INIT_G_cmdtable() do { \
7417 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7418} while (0)
7419
7420static int builtinloc = -1; /* index in path of %builtin, or -1 */
7421
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007422
7423static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007424tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007425{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007426#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007427 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007428 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007429 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007430 while (*envp)
7431 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007432 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007433 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007434 /* re-exec ourselves with the new arguments */
7435 execve(bb_busybox_exec_path, argv, envp);
7436 /* If they called chroot or otherwise made the binary no longer
7437 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007438 }
7439#endif
7440
7441 repeat:
7442#ifdef SYSV
7443 do {
7444 execve(cmd, argv, envp);
7445 } while (errno == EINTR);
7446#else
7447 execve(cmd, argv, envp);
7448#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007449 if (cmd == (char*) bb_busybox_exec_path) {
7450 /* We already visited ENOEXEC branch below, don't do it again */
7451//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007452 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007453 return;
7454 }
7455 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007456 /* Run "cmd" as a shell script:
7457 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7458 * "If the execve() function fails with ENOEXEC, the shell
7459 * shall execute a command equivalent to having a shell invoked
7460 * with the command name as its first operand,
7461 * with any remaining arguments passed to the new shell"
7462 *
7463 * That is, do not use $SHELL, user's shell, or /bin/sh;
7464 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007465 *
7466 * Note that bash reads ~80 chars of the file, and if it sees
7467 * a zero byte before it sees newline, it doesn't try to
7468 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007469 * message and exit code 126. For one, this prevents attempts
7470 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007471 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007472 char **ap;
7473 char **new;
7474
7475 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007476 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007477 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7478 new[0] = (char*) "ash";
7479 new[1] = cmd;
7480 ap = new + 2;
7481 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007482 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007483 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007484 argv = new;
7485 goto repeat;
7486 }
7487}
7488
7489/*
7490 * Exec a program. Never returns. If you change this routine, you may
7491 * have to change the find_command routine as well.
7492 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007493static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007494static void
7495shellexec(char **argv, const char *path, int idx)
7496{
7497 char *cmdname;
7498 int e;
7499 char **envp;
7500 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007501 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007502
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007503 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007504 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007505 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007506#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007507 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007508#endif
7509 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007510 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007511 if (applet_no >= 0) {
7512 /* We tried execing ourself, but it didn't work.
7513 * Maybe /proc/self/exe doesn't exist?
7514 * Try $PATH search.
7515 */
7516 goto try_PATH;
7517 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007518 e = errno;
7519 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007520 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007521 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007522 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007523 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007524 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007525 if (errno != ENOENT && errno != ENOTDIR)
7526 e = errno;
7527 }
7528 stunalloc(cmdname);
7529 }
7530 }
7531
7532 /* Map to POSIX errors */
7533 switch (e) {
7534 case EACCES:
7535 exerrno = 126;
7536 break;
7537 case ENOENT:
7538 exerrno = 127;
7539 break;
7540 default:
7541 exerrno = 2;
7542 break;
7543 }
7544 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007545 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7546 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007547 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7548 /* NOTREACHED */
7549}
7550
7551static void
7552printentry(struct tblentry *cmdp)
7553{
7554 int idx;
7555 const char *path;
7556 char *name;
7557
7558 idx = cmdp->param.index;
7559 path = pathval();
7560 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007561 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007562 stunalloc(name);
7563 } while (--idx >= 0);
7564 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7565}
7566
7567/*
7568 * Clear out command entries. The argument specifies the first entry in
7569 * PATH which has changed.
7570 */
7571static void
7572clearcmdentry(int firstchange)
7573{
7574 struct tblentry **tblp;
7575 struct tblentry **pp;
7576 struct tblentry *cmdp;
7577
7578 INT_OFF;
7579 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7580 pp = tblp;
7581 while ((cmdp = *pp) != NULL) {
7582 if ((cmdp->cmdtype == CMDNORMAL &&
7583 cmdp->param.index >= firstchange)
7584 || (cmdp->cmdtype == CMDBUILTIN &&
7585 builtinloc >= firstchange)
7586 ) {
7587 *pp = cmdp->next;
7588 free(cmdp);
7589 } else {
7590 pp = &cmdp->next;
7591 }
7592 }
7593 }
7594 INT_ON;
7595}
7596
7597/*
7598 * Locate a command in the command hash table. If "add" is nonzero,
7599 * add the command to the table if it is not already present. The
7600 * variable "lastcmdentry" is set to point to the address of the link
7601 * pointing to the entry, so that delete_cmd_entry can delete the
7602 * entry.
7603 *
7604 * Interrupts must be off if called with add != 0.
7605 */
7606static struct tblentry **lastcmdentry;
7607
7608static struct tblentry *
7609cmdlookup(const char *name, int add)
7610{
7611 unsigned int hashval;
7612 const char *p;
7613 struct tblentry *cmdp;
7614 struct tblentry **pp;
7615
7616 p = name;
7617 hashval = (unsigned char)*p << 4;
7618 while (*p)
7619 hashval += (unsigned char)*p++;
7620 hashval &= 0x7FFF;
7621 pp = &cmdtable[hashval % CMDTABLESIZE];
7622 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7623 if (strcmp(cmdp->cmdname, name) == 0)
7624 break;
7625 pp = &cmdp->next;
7626 }
7627 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007628 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7629 + strlen(name)
7630 /* + 1 - already done because
7631 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007632 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007633 cmdp->cmdtype = CMDUNKNOWN;
7634 strcpy(cmdp->cmdname, name);
7635 }
7636 lastcmdentry = pp;
7637 return cmdp;
7638}
7639
7640/*
7641 * Delete the command entry returned on the last lookup.
7642 */
7643static void
7644delete_cmd_entry(void)
7645{
7646 struct tblentry *cmdp;
7647
7648 INT_OFF;
7649 cmdp = *lastcmdentry;
7650 *lastcmdentry = cmdp->next;
7651 if (cmdp->cmdtype == CMDFUNCTION)
7652 freefunc(cmdp->param.func);
7653 free(cmdp);
7654 INT_ON;
7655}
7656
7657/*
7658 * Add a new command entry, replacing any existing command entry for
7659 * the same name - except special builtins.
7660 */
7661static void
7662addcmdentry(char *name, struct cmdentry *entry)
7663{
7664 struct tblentry *cmdp;
7665
7666 cmdp = cmdlookup(name, 1);
7667 if (cmdp->cmdtype == CMDFUNCTION) {
7668 freefunc(cmdp->param.func);
7669 }
7670 cmdp->cmdtype = entry->cmdtype;
7671 cmdp->param = entry->u;
7672 cmdp->rehash = 0;
7673}
7674
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007675static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007676hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007677{
7678 struct tblentry **pp;
7679 struct tblentry *cmdp;
7680 int c;
7681 struct cmdentry entry;
7682 char *name;
7683
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007684 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007685 clearcmdentry(0);
7686 return 0;
7687 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007688
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007689 if (*argptr == NULL) {
7690 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7691 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7692 if (cmdp->cmdtype == CMDNORMAL)
7693 printentry(cmdp);
7694 }
7695 }
7696 return 0;
7697 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007698
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007699 c = 0;
7700 while ((name = *argptr) != NULL) {
7701 cmdp = cmdlookup(name, 0);
7702 if (cmdp != NULL
7703 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007704 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7705 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007706 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007707 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007708 find_command(name, &entry, DO_ERR, pathval());
7709 if (entry.cmdtype == CMDUNKNOWN)
7710 c = 1;
7711 argptr++;
7712 }
7713 return c;
7714}
7715
7716/*
7717 * Called when a cd is done. Marks all commands so the next time they
7718 * are executed they will be rehashed.
7719 */
7720static void
7721hashcd(void)
7722{
7723 struct tblentry **pp;
7724 struct tblentry *cmdp;
7725
7726 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7727 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007728 if (cmdp->cmdtype == CMDNORMAL
7729 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007730 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007731 && builtinloc > 0)
7732 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007733 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007734 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007735 }
7736 }
7737}
7738
7739/*
7740 * Fix command hash table when PATH changed.
7741 * Called before PATH is changed. The argument is the new value of PATH;
7742 * pathval() still returns the old value at this point.
7743 * Called with interrupts off.
7744 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007745static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007746changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007747{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007748 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007749 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007750 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007751 int idx_bltin;
7752
7753 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007754 firstchange = 9999; /* assume no change */
7755 idx = 0;
7756 idx_bltin = -1;
7757 for (;;) {
7758 if (*old != *new) {
7759 firstchange = idx;
7760 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007761 || (*old == ':' && *new == '\0')
7762 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007763 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007764 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007765 old = new; /* ignore subsequent differences */
7766 }
7767 if (*new == '\0')
7768 break;
7769 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7770 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007771 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007772 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007773 new++;
7774 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007775 }
7776 if (builtinloc < 0 && idx_bltin >= 0)
7777 builtinloc = idx_bltin; /* zap builtins */
7778 if (builtinloc >= 0 && idx_bltin < 0)
7779 firstchange = 0;
7780 clearcmdentry(firstchange);
7781 builtinloc = idx_bltin;
7782}
7783
7784#define TEOF 0
7785#define TNL 1
7786#define TREDIR 2
7787#define TWORD 3
7788#define TSEMI 4
7789#define TBACKGND 5
7790#define TAND 6
7791#define TOR 7
7792#define TPIPE 8
7793#define TLP 9
7794#define TRP 10
7795#define TENDCASE 11
7796#define TENDBQUOTE 12
7797#define TNOT 13
7798#define TCASE 14
7799#define TDO 15
7800#define TDONE 16
7801#define TELIF 17
7802#define TELSE 18
7803#define TESAC 19
7804#define TFI 20
7805#define TFOR 21
7806#define TIF 22
7807#define TIN 23
7808#define TTHEN 24
7809#define TUNTIL 25
7810#define TWHILE 26
7811#define TBEGIN 27
7812#define TEND 28
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007813typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007814
7815/* first char is indicating which tokens mark the end of a list */
7816static const char *const tokname_array[] = {
7817 "\1end of file",
7818 "\0newline",
7819 "\0redirection",
7820 "\0word",
7821 "\0;",
7822 "\0&",
7823 "\0&&",
7824 "\0||",
7825 "\0|",
7826 "\0(",
7827 "\1)",
7828 "\1;;",
7829 "\1`",
7830#define KWDOFFSET 13
7831 /* the following are keywords */
7832 "\0!",
7833 "\0case",
7834 "\1do",
7835 "\1done",
7836 "\1elif",
7837 "\1else",
7838 "\1esac",
7839 "\1fi",
7840 "\0for",
7841 "\0if",
7842 "\0in",
7843 "\1then",
7844 "\0until",
7845 "\0while",
7846 "\0{",
7847 "\1}",
7848};
7849
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007850/* Wrapper around strcmp for qsort/bsearch/... */
7851static int
7852pstrcmp(const void *a, const void *b)
7853{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007854 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007855}
7856
7857static const char *const *
7858findkwd(const char *s)
7859{
7860 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007861 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7862 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007863}
7864
7865/*
7866 * Locate and print what a word is...
7867 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007868static int
7869describe_command(char *command, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007870{
7871 struct cmdentry entry;
7872 struct tblentry *cmdp;
7873#if ENABLE_ASH_ALIAS
7874 const struct alias *ap;
7875#endif
7876 const char *path = pathval();
7877
7878 if (describe_command_verbose) {
7879 out1str(command);
7880 }
7881
7882 /* First look at the keywords */
7883 if (findkwd(command)) {
7884 out1str(describe_command_verbose ? " is a shell keyword" : command);
7885 goto out;
7886 }
7887
7888#if ENABLE_ASH_ALIAS
7889 /* Then look at the aliases */
7890 ap = lookupalias(command, 0);
7891 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007892 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007893 out1str("alias ");
7894 printalias(ap);
7895 return 0;
7896 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007897 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007898 goto out;
7899 }
7900#endif
7901 /* Then check if it is a tracked alias */
7902 cmdp = cmdlookup(command, 0);
7903 if (cmdp != NULL) {
7904 entry.cmdtype = cmdp->cmdtype;
7905 entry.u = cmdp->param;
7906 } else {
7907 /* Finally use brute force */
7908 find_command(command, &entry, DO_ABS, path);
7909 }
7910
7911 switch (entry.cmdtype) {
7912 case CMDNORMAL: {
7913 int j = entry.u.index;
7914 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007915 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007916 p = command;
7917 } else {
7918 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007919 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007920 stunalloc(p);
7921 } while (--j >= 0);
7922 }
7923 if (describe_command_verbose) {
7924 out1fmt(" is%s %s",
7925 (cmdp ? " a tracked alias for" : nullstr), p
7926 );
7927 } else {
7928 out1str(p);
7929 }
7930 break;
7931 }
7932
7933 case CMDFUNCTION:
7934 if (describe_command_verbose) {
7935 out1str(" is a shell function");
7936 } else {
7937 out1str(command);
7938 }
7939 break;
7940
7941 case CMDBUILTIN:
7942 if (describe_command_verbose) {
7943 out1fmt(" is a %sshell builtin",
7944 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7945 "special " : nullstr
7946 );
7947 } else {
7948 out1str(command);
7949 }
7950 break;
7951
7952 default:
7953 if (describe_command_verbose) {
7954 out1str(": not found\n");
7955 }
7956 return 127;
7957 }
7958 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01007959 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007960 return 0;
7961}
7962
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007963static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007964typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007965{
Denis Vlasenko46846e22007-05-20 13:08:31 +00007966 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007967 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00007968 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007969
Denis Vlasenko46846e22007-05-20 13:08:31 +00007970 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00007971 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007972 i++;
7973 verbose = 0;
7974 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00007975 while (argv[i]) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007976 err |= describe_command(argv[i++], verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007977 }
7978 return err;
7979}
7980
7981#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007982static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007983commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007984{
7985 int c;
7986 enum {
7987 VERIFY_BRIEF = 1,
7988 VERIFY_VERBOSE = 2,
7989 } verify = 0;
7990
7991 while ((c = nextopt("pvV")) != '\0')
7992 if (c == 'V')
7993 verify |= VERIFY_VERBOSE;
7994 else if (c == 'v')
7995 verify |= VERIFY_BRIEF;
7996#if DEBUG
7997 else if (c != 'p')
7998 abort();
7999#endif
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008000 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8001 if (verify && (*argptr != NULL)) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008002 return describe_command(*argptr, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008003 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008004
8005 return 0;
8006}
8007#endif
8008
8009
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008010/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00008011
Denis Vlasenko340299a2008-11-21 10:36:36 +00008012static int funcblocksize; /* size of structures in function */
8013static int funcstringsize; /* size of strings in node */
8014static void *funcblock; /* block to allocate function from */
8015static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008016
Eric Andersencb57d552001-06-28 07:25:16 +00008017/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008018#define EV_EXIT 01 /* exit after evaluating tree */
8019#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersenc470f442003-07-28 09:56:35 +00008020#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00008021
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02008022static const uint8_t nodesize[N_NUMBER] = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008023 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8024 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8025 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8026 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8027 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8028 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8029 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8030 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8031 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8032 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8033 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8034 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8035 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8036 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8037 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8038 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8039 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008040#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008041 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008042#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008043 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8044 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8045 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8046 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8047 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8048 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8049 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8050 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8051 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008052};
8053
8054static void calcsize(union node *n);
8055
8056static void
8057sizenodelist(struct nodelist *lp)
8058{
8059 while (lp) {
8060 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8061 calcsize(lp->n);
8062 lp = lp->next;
8063 }
8064}
8065
8066static void
8067calcsize(union node *n)
8068{
8069 if (n == NULL)
8070 return;
8071 funcblocksize += nodesize[n->type];
8072 switch (n->type) {
8073 case NCMD:
8074 calcsize(n->ncmd.redirect);
8075 calcsize(n->ncmd.args);
8076 calcsize(n->ncmd.assign);
8077 break;
8078 case NPIPE:
8079 sizenodelist(n->npipe.cmdlist);
8080 break;
8081 case NREDIR:
8082 case NBACKGND:
8083 case NSUBSHELL:
8084 calcsize(n->nredir.redirect);
8085 calcsize(n->nredir.n);
8086 break;
8087 case NAND:
8088 case NOR:
8089 case NSEMI:
8090 case NWHILE:
8091 case NUNTIL:
8092 calcsize(n->nbinary.ch2);
8093 calcsize(n->nbinary.ch1);
8094 break;
8095 case NIF:
8096 calcsize(n->nif.elsepart);
8097 calcsize(n->nif.ifpart);
8098 calcsize(n->nif.test);
8099 break;
8100 case NFOR:
8101 funcstringsize += strlen(n->nfor.var) + 1;
8102 calcsize(n->nfor.body);
8103 calcsize(n->nfor.args);
8104 break;
8105 case NCASE:
8106 calcsize(n->ncase.cases);
8107 calcsize(n->ncase.expr);
8108 break;
8109 case NCLIST:
8110 calcsize(n->nclist.body);
8111 calcsize(n->nclist.pattern);
8112 calcsize(n->nclist.next);
8113 break;
8114 case NDEFUN:
8115 case NARG:
8116 sizenodelist(n->narg.backquote);
8117 funcstringsize += strlen(n->narg.text) + 1;
8118 calcsize(n->narg.next);
8119 break;
8120 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008121#if ENABLE_ASH_BASH_COMPAT
8122 case NTO2:
8123#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008124 case NCLOBBER:
8125 case NFROM:
8126 case NFROMTO:
8127 case NAPPEND:
8128 calcsize(n->nfile.fname);
8129 calcsize(n->nfile.next);
8130 break;
8131 case NTOFD:
8132 case NFROMFD:
8133 calcsize(n->ndup.vname);
8134 calcsize(n->ndup.next);
8135 break;
8136 case NHERE:
8137 case NXHERE:
8138 calcsize(n->nhere.doc);
8139 calcsize(n->nhere.next);
8140 break;
8141 case NNOT:
8142 calcsize(n->nnot.com);
8143 break;
8144 };
8145}
8146
8147static char *
8148nodeckstrdup(char *s)
8149{
8150 char *rtn = funcstring;
8151
8152 strcpy(funcstring, s);
8153 funcstring += strlen(s) + 1;
8154 return rtn;
8155}
8156
8157static union node *copynode(union node *);
8158
8159static struct nodelist *
8160copynodelist(struct nodelist *lp)
8161{
8162 struct nodelist *start;
8163 struct nodelist **lpp;
8164
8165 lpp = &start;
8166 while (lp) {
8167 *lpp = funcblock;
8168 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8169 (*lpp)->n = copynode(lp->n);
8170 lp = lp->next;
8171 lpp = &(*lpp)->next;
8172 }
8173 *lpp = NULL;
8174 return start;
8175}
8176
8177static union node *
8178copynode(union node *n)
8179{
8180 union node *new;
8181
8182 if (n == NULL)
8183 return NULL;
8184 new = funcblock;
8185 funcblock = (char *) funcblock + nodesize[n->type];
8186
8187 switch (n->type) {
8188 case NCMD:
8189 new->ncmd.redirect = copynode(n->ncmd.redirect);
8190 new->ncmd.args = copynode(n->ncmd.args);
8191 new->ncmd.assign = copynode(n->ncmd.assign);
8192 break;
8193 case NPIPE:
8194 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008195 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008196 break;
8197 case NREDIR:
8198 case NBACKGND:
8199 case NSUBSHELL:
8200 new->nredir.redirect = copynode(n->nredir.redirect);
8201 new->nredir.n = copynode(n->nredir.n);
8202 break;
8203 case NAND:
8204 case NOR:
8205 case NSEMI:
8206 case NWHILE:
8207 case NUNTIL:
8208 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8209 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8210 break;
8211 case NIF:
8212 new->nif.elsepart = copynode(n->nif.elsepart);
8213 new->nif.ifpart = copynode(n->nif.ifpart);
8214 new->nif.test = copynode(n->nif.test);
8215 break;
8216 case NFOR:
8217 new->nfor.var = nodeckstrdup(n->nfor.var);
8218 new->nfor.body = copynode(n->nfor.body);
8219 new->nfor.args = copynode(n->nfor.args);
8220 break;
8221 case NCASE:
8222 new->ncase.cases = copynode(n->ncase.cases);
8223 new->ncase.expr = copynode(n->ncase.expr);
8224 break;
8225 case NCLIST:
8226 new->nclist.body = copynode(n->nclist.body);
8227 new->nclist.pattern = copynode(n->nclist.pattern);
8228 new->nclist.next = copynode(n->nclist.next);
8229 break;
8230 case NDEFUN:
8231 case NARG:
8232 new->narg.backquote = copynodelist(n->narg.backquote);
8233 new->narg.text = nodeckstrdup(n->narg.text);
8234 new->narg.next = copynode(n->narg.next);
8235 break;
8236 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008237#if ENABLE_ASH_BASH_COMPAT
8238 case NTO2:
8239#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008240 case NCLOBBER:
8241 case NFROM:
8242 case NFROMTO:
8243 case NAPPEND:
8244 new->nfile.fname = copynode(n->nfile.fname);
8245 new->nfile.fd = n->nfile.fd;
8246 new->nfile.next = copynode(n->nfile.next);
8247 break;
8248 case NTOFD:
8249 case NFROMFD:
8250 new->ndup.vname = copynode(n->ndup.vname);
8251 new->ndup.dupfd = n->ndup.dupfd;
8252 new->ndup.fd = n->ndup.fd;
8253 new->ndup.next = copynode(n->ndup.next);
8254 break;
8255 case NHERE:
8256 case NXHERE:
8257 new->nhere.doc = copynode(n->nhere.doc);
8258 new->nhere.fd = n->nhere.fd;
8259 new->nhere.next = copynode(n->nhere.next);
8260 break;
8261 case NNOT:
8262 new->nnot.com = copynode(n->nnot.com);
8263 break;
8264 };
8265 new->type = n->type;
8266 return new;
8267}
8268
8269/*
8270 * Make a copy of a parse tree.
8271 */
8272static struct funcnode *
8273copyfunc(union node *n)
8274{
8275 struct funcnode *f;
8276 size_t blocksize;
8277
8278 funcblocksize = offsetof(struct funcnode, n);
8279 funcstringsize = 0;
8280 calcsize(n);
8281 blocksize = funcblocksize;
8282 f = ckmalloc(blocksize + funcstringsize);
8283 funcblock = (char *) f + offsetof(struct funcnode, n);
8284 funcstring = (char *) f + blocksize;
8285 copynode(n);
8286 f->count = 0;
8287 return f;
8288}
8289
8290/*
8291 * Define a shell function.
8292 */
8293static void
8294defun(char *name, union node *func)
8295{
8296 struct cmdentry entry;
8297
8298 INT_OFF;
8299 entry.cmdtype = CMDFUNCTION;
8300 entry.u.func = copyfunc(func);
8301 addcmdentry(name, &entry);
8302 INT_ON;
8303}
8304
Denis Vlasenko4b875702009-03-19 13:30:04 +00008305/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008306#define SKIPBREAK (1 << 0)
8307#define SKIPCONT (1 << 1)
8308#define SKIPFUNC (1 << 2)
8309#define SKIPFILE (1 << 3)
8310#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008311static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008312static int skipcount; /* number of levels to skip */
8313static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008314static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008315
Denis Vlasenko4b875702009-03-19 13:30:04 +00008316/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008317static int evalstring(char *s, int mask);
8318
Denis Vlasenko4b875702009-03-19 13:30:04 +00008319/* Called to execute a trap.
8320 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008321 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008322 *
8323 * Perhaps we should avoid entering new trap handlers
8324 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008325 */
8326static int
8327dotrap(void)
8328{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008329 uint8_t *g;
8330 int sig;
8331 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008332
8333 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008334 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008335 xbarrier();
8336
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008337 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008338 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8339 int want_exexit;
8340 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008341
Denis Vlasenko4b875702009-03-19 13:30:04 +00008342 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008343 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008344 t = trap[sig];
8345 /* non-trapped SIGINT is handled separately by raise_interrupt,
8346 * don't upset it by resetting gotsig[SIGINT-1] */
8347 if (sig == SIGINT && !t)
8348 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008349
8350 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008351 *g = 0;
8352 if (!t)
8353 continue;
8354 want_exexit = evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008355 exitstatus = savestatus;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008356 if (want_exexit) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008357 TRACE(("dotrap returns %d\n", want_exexit));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008358 return want_exexit;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008359 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008360 }
8361
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008362 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008363 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008364}
8365
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008366/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008367static void evalloop(union node *, int);
8368static void evalfor(union node *, int);
8369static void evalcase(union node *, int);
8370static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008371static void expredir(union node *);
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008372static void evalpipe(union node *, int);
8373static void evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008374static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008375static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008376
Eric Andersen62483552001-07-10 06:09:16 +00008377/*
Eric Andersenc470f442003-07-28 09:56:35 +00008378 * Evaluate a parse tree. The value is left in the global variable
8379 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008380 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008381static void
Eric Andersenc470f442003-07-28 09:56:35 +00008382evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008383{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008384 struct jmploc *volatile savehandler = exception_handler;
8385 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008386 int checkexit = 0;
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008387 void (*evalfn)(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008388 int status;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008389 int int_level;
8390
8391 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008392
Eric Andersenc470f442003-07-28 09:56:35 +00008393 if (n == NULL) {
8394 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008395 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008396 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008397 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008398
8399 exception_handler = &jmploc;
8400 {
8401 int err = setjmp(jmploc.loc);
8402 if (err) {
8403 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008404 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008405 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8406 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008407 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008408 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008409 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008410 TRACE(("exception %d in evaltree, propagating err=%d\n",
8411 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008412 exception_handler = savehandler;
8413 longjmp(exception_handler->loc, err);
8414 }
8415 }
8416
Eric Andersenc470f442003-07-28 09:56:35 +00008417 switch (n->type) {
8418 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008419#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008420 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008421 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008422 break;
8423#endif
8424 case NNOT:
8425 evaltree(n->nnot.com, EV_TESTED);
8426 status = !exitstatus;
8427 goto setstatus;
8428 case NREDIR:
8429 expredir(n->nredir.redirect);
8430 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8431 if (!status) {
8432 evaltree(n->nredir.n, flags & EV_TESTED);
8433 status = exitstatus;
8434 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008435 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008436 goto setstatus;
8437 case NCMD:
8438 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008439 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008440 if (eflag && !(flags & EV_TESTED))
8441 checkexit = ~0;
8442 goto calleval;
8443 case NFOR:
8444 evalfn = evalfor;
8445 goto calleval;
8446 case NWHILE:
8447 case NUNTIL:
8448 evalfn = evalloop;
8449 goto calleval;
8450 case NSUBSHELL:
8451 case NBACKGND:
8452 evalfn = evalsubshell;
8453 goto calleval;
8454 case NPIPE:
8455 evalfn = evalpipe;
8456 goto checkexit;
8457 case NCASE:
8458 evalfn = evalcase;
8459 goto calleval;
8460 case NAND:
8461 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008462 case NSEMI: {
8463
Eric Andersenc470f442003-07-28 09:56:35 +00008464#if NAND + 1 != NOR
8465#error NAND + 1 != NOR
8466#endif
8467#if NOR + 1 != NSEMI
8468#error NOR + 1 != NSEMI
8469#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008470 unsigned is_or = n->type - NAND;
Eric Andersenc470f442003-07-28 09:56:35 +00008471 evaltree(
8472 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008473 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008474 );
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008475 if (!exitstatus == is_or)
Eric Andersenc470f442003-07-28 09:56:35 +00008476 break;
8477 if (!evalskip) {
8478 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008479 evaln:
Eric Andersenc470f442003-07-28 09:56:35 +00008480 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008481 calleval:
Eric Andersenc470f442003-07-28 09:56:35 +00008482 evalfn(n, flags);
8483 break;
8484 }
8485 break;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008486 }
Eric Andersenc470f442003-07-28 09:56:35 +00008487 case NIF:
8488 evaltree(n->nif.test, EV_TESTED);
8489 if (evalskip)
8490 break;
8491 if (exitstatus == 0) {
8492 n = n->nif.ifpart;
8493 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008494 }
8495 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008496 n = n->nif.elsepart;
8497 goto evaln;
8498 }
8499 goto success;
8500 case NDEFUN:
8501 defun(n->narg.text, n->narg.next);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008502 success:
Eric Andersenc470f442003-07-28 09:56:35 +00008503 status = 0;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008504 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008505 exitstatus = status;
8506 break;
8507 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008508
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008509 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008510 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008511
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008512 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008513 /* Order of checks below is important:
8514 * signal handlers trigger before exit caused by "set -e".
8515 */
8516 if (pending_sig && dotrap())
8517 goto exexit;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008518 if (checkexit & exitstatus)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008519 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008520
8521 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008522 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008523 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008524 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008525
8526 RESTORE_INT(int_level);
8527 TRACE(("leaving evaltree (no interrupts)\n"));
Eric Andersen62483552001-07-10 06:09:16 +00008528}
8529
Eric Andersenc470f442003-07-28 09:56:35 +00008530#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8531static
8532#endif
8533void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8534
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008535static void
Eric Andersenc470f442003-07-28 09:56:35 +00008536evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008537{
8538 int status;
8539
8540 loopnest++;
8541 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008542 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008543 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008544 int i;
8545
Eric Andersencb57d552001-06-28 07:25:16 +00008546 evaltree(n->nbinary.ch1, EV_TESTED);
8547 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008548 skipping:
8549 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008550 evalskip = 0;
8551 continue;
8552 }
8553 if (evalskip == SKIPBREAK && --skipcount <= 0)
8554 evalskip = 0;
8555 break;
8556 }
Eric Andersenc470f442003-07-28 09:56:35 +00008557 i = exitstatus;
8558 if (n->type != NWHILE)
8559 i = !i;
8560 if (i != 0)
8561 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008562 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008563 status = exitstatus;
8564 if (evalskip)
8565 goto skipping;
8566 }
8567 loopnest--;
8568 exitstatus = status;
8569}
8570
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008571static void
Eric Andersenc470f442003-07-28 09:56:35 +00008572evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008573{
8574 struct arglist arglist;
8575 union node *argp;
8576 struct strlist *sp;
8577 struct stackmark smark;
8578
8579 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008580 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008581 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008582 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008583 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00008584 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008585 if (evalskip)
8586 goto out;
8587 }
8588 *arglist.lastp = NULL;
8589
8590 exitstatus = 0;
8591 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008592 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008593 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008594 setvar0(n->nfor.var, sp->text);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008595 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008596 if (evalskip) {
8597 if (evalskip == SKIPCONT && --skipcount <= 0) {
8598 evalskip = 0;
8599 continue;
8600 }
8601 if (evalskip == SKIPBREAK && --skipcount <= 0)
8602 evalskip = 0;
8603 break;
8604 }
8605 }
8606 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008607 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008608 popstackmark(&smark);
8609}
8610
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008611static void
Eric Andersenc470f442003-07-28 09:56:35 +00008612evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008613{
8614 union node *cp;
8615 union node *patp;
8616 struct arglist arglist;
8617 struct stackmark smark;
8618
8619 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008620 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008621 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008622 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008623 exitstatus = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008624 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8625 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008626 if (casematch(patp, arglist.list->text)) {
8627 if (evalskip == 0) {
8628 evaltree(cp->nclist.body, flags);
8629 }
8630 goto out;
8631 }
8632 }
8633 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008634 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008635 popstackmark(&smark);
8636}
8637
Eric Andersenc470f442003-07-28 09:56:35 +00008638/*
8639 * Kick off a subshell to evaluate a tree.
8640 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008641static void
Eric Andersenc470f442003-07-28 09:56:35 +00008642evalsubshell(union node *n, int flags)
8643{
8644 struct job *jp;
8645 int backgnd = (n->type == NBACKGND);
8646 int status;
8647
8648 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008649 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008650 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008651 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008652 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008653 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008654 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008655 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008656 flags |= EV_EXIT;
8657 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008658 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008659 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008660 redirect(n->nredir.redirect, 0);
8661 evaltreenr(n->nredir.n, flags);
8662 /* never returns */
8663 }
8664 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008665 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008666 status = waitforjob(jp);
8667 exitstatus = status;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008668 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008669}
8670
Eric Andersenc470f442003-07-28 09:56:35 +00008671/*
8672 * Compute the names of the files in a redirection list.
8673 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008674static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008675static void
8676expredir(union node *n)
8677{
8678 union node *redir;
8679
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008680 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008681 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008682
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008683 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008684 fn.lastp = &fn.list;
8685 switch (redir->type) {
8686 case NFROMTO:
8687 case NFROM:
8688 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008689#if ENABLE_ASH_BASH_COMPAT
8690 case NTO2:
8691#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008692 case NCLOBBER:
8693 case NAPPEND:
8694 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008695 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008696#if ENABLE_ASH_BASH_COMPAT
8697 store_expfname:
8698#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008699#if 0
8700// By the design of stack allocator, the loop of this kind:
8701// while true; do while true; do break; done </dev/null; done
8702// will look like a memory leak: ash plans to free expfname's
8703// of "/dev/null" as soon as it finishes running the loop
8704// (in this case, never).
8705// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008706 if (redir->nfile.expfname)
8707 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008708// It results in corrupted state of stacked allocations.
8709#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008710 redir->nfile.expfname = fn.list->text;
8711 break;
8712 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008713 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008714 if (redir->ndup.vname) {
8715 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008716 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008717 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008718#if ENABLE_ASH_BASH_COMPAT
8719//FIXME: we used expandarg with different args!
8720 if (!isdigit_str9(fn.list->text)) {
8721 /* >&file, not >&fd */
8722 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8723 ash_msg_and_raise_error("redir error");
8724 redir->type = NTO2;
8725 goto store_expfname;
8726 }
8727#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008728 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008729 }
8730 break;
8731 }
8732 }
8733}
8734
Eric Andersencb57d552001-06-28 07:25:16 +00008735/*
Eric Andersencb57d552001-06-28 07:25:16 +00008736 * Evaluate a pipeline. All the processes in the pipeline are children
8737 * of the process creating the pipeline. (This differs from some versions
8738 * of the shell, which make the last process in a pipeline the parent
8739 * of all the rest.)
8740 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008741static void
Eric Andersenc470f442003-07-28 09:56:35 +00008742evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008743{
8744 struct job *jp;
8745 struct nodelist *lp;
8746 int pipelen;
8747 int prevfd;
8748 int pip[2];
8749
Eric Andersenc470f442003-07-28 09:56:35 +00008750 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008751 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008752 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008753 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008754 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008755 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008756 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008757 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008758 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008759 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008760 pip[1] = -1;
8761 if (lp->next) {
8762 if (pipe(pip) < 0) {
8763 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008764 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008765 }
8766 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008767 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008768 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008769 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008770 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008771 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008772 if (prevfd > 0) {
8773 dup2(prevfd, 0);
8774 close(prevfd);
8775 }
8776 if (pip[1] > 1) {
8777 dup2(pip[1], 1);
8778 close(pip[1]);
8779 }
Eric Andersenc470f442003-07-28 09:56:35 +00008780 evaltreenr(lp->n, flags);
8781 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008782 }
8783 if (prevfd >= 0)
8784 close(prevfd);
8785 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008786 /* Don't want to trigger debugging */
8787 if (pip[1] != -1)
8788 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008789 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008790 if (n->npipe.pipe_backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008791 exitstatus = waitforjob(jp);
8792 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00008793 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008794 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008795}
8796
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008797/*
8798 * Controls whether the shell is interactive or not.
8799 */
8800static void
8801setinteractive(int on)
8802{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008803 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008804
8805 if (++on == is_interactive)
8806 return;
8807 is_interactive = on;
8808 setsignal(SIGINT);
8809 setsignal(SIGQUIT);
8810 setsignal(SIGTERM);
8811#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8812 if (is_interactive > 1) {
8813 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008814 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008815
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008816 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008817 /* note: ash and hush share this string */
8818 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008819 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8820 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008821 bb_banner,
8822 "built-in shell (ash)"
8823 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008824 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008825 }
8826 }
8827#endif
8828}
8829
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008830static void
8831optschanged(void)
8832{
8833#if DEBUG
8834 opentrace();
8835#endif
8836 setinteractive(iflag);
8837 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008838#if ENABLE_FEATURE_EDITING_VI
8839 if (viflag)
8840 line_input_state->flags |= VI_MODE;
8841 else
8842 line_input_state->flags &= ~VI_MODE;
8843#else
8844 viflag = 0; /* forcibly keep the option off */
8845#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008846}
8847
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008848static struct localvar *localvars;
8849
8850/*
8851 * Called after a function returns.
8852 * Interrupts must be off.
8853 */
8854static void
8855poplocalvars(void)
8856{
8857 struct localvar *lvp;
8858 struct var *vp;
8859
8860 while ((lvp = localvars) != NULL) {
8861 localvars = lvp->next;
8862 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008863 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008864 if (vp == NULL) { /* $- saved */
8865 memcpy(optlist, lvp->text, sizeof(optlist));
8866 free((char*)lvp->text);
8867 optschanged();
8868 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008869 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008870 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008871 if (vp->var_func)
8872 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008873 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008874 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008875 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008876 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008877 }
8878 free(lvp);
8879 }
8880}
8881
8882static int
8883evalfun(struct funcnode *func, int argc, char **argv, int flags)
8884{
8885 volatile struct shparam saveparam;
8886 struct localvar *volatile savelocalvars;
8887 struct jmploc *volatile savehandler;
8888 struct jmploc jmploc;
8889 int e;
8890
8891 saveparam = shellparam;
8892 savelocalvars = localvars;
8893 e = setjmp(jmploc.loc);
8894 if (e) {
8895 goto funcdone;
8896 }
8897 INT_OFF;
8898 savehandler = exception_handler;
8899 exception_handler = &jmploc;
8900 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008901 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008902 func->count++;
8903 funcnest++;
8904 INT_ON;
8905 shellparam.nparam = argc - 1;
8906 shellparam.p = argv + 1;
8907#if ENABLE_ASH_GETOPTS
8908 shellparam.optind = 1;
8909 shellparam.optoff = -1;
8910#endif
8911 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008912 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008913 INT_OFF;
8914 funcnest--;
8915 freefunc(func);
8916 poplocalvars();
8917 localvars = savelocalvars;
8918 freeparam(&shellparam);
8919 shellparam = saveparam;
8920 exception_handler = savehandler;
8921 INT_ON;
8922 evalskip &= ~SKIPFUNC;
8923 return e;
8924}
8925
Denis Vlasenko131ae172007-02-18 13:00:19 +00008926#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008927static char **
8928parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008929{
8930 char *cp, c;
8931
8932 for (;;) {
8933 cp = *++argv;
8934 if (!cp)
8935 return 0;
8936 if (*cp++ != '-')
8937 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008938 c = *cp++;
8939 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008940 break;
8941 if (c == '-' && !*cp) {
8942 argv++;
8943 break;
8944 }
8945 do {
8946 switch (c) {
8947 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00008948 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00008949 break;
8950 default:
8951 /* run 'typecmd' for other options */
8952 return 0;
8953 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00008954 c = *cp++;
8955 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00008956 }
8957 return argv;
8958}
8959#endif
8960
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008961/*
8962 * Make a variable a local variable. When a variable is made local, it's
8963 * value and flags are saved in a localvar structure. The saved values
8964 * will be restored when the shell function returns. We handle the name
8965 * "-" as a special case.
8966 */
8967static void
8968mklocal(char *name)
8969{
8970 struct localvar *lvp;
8971 struct var **vpp;
8972 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008973 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008974
8975 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008976 /* Cater for duplicate "local". Examples:
8977 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
8978 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
8979 */
8980 lvp = localvars;
8981 while (lvp) {
8982 if (varcmp(lvp->vp->var_text, name) == 0) {
8983 if (eq)
8984 setvareq(name, 0);
8985 /* else:
8986 * it's a duplicate "local VAR" declaration, do nothing
8987 */
8988 return;
8989 }
8990 lvp = lvp->next;
8991 }
8992
8993 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008994 if (LONE_DASH(name)) {
8995 char *p;
8996 p = ckmalloc(sizeof(optlist));
8997 lvp->text = memcpy(p, optlist, sizeof(optlist));
8998 vp = NULL;
8999 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009000 vpp = hashvar(name);
9001 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009002 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009003 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009004 if (eq)
9005 setvareq(name, VSTRFIXED);
9006 else
9007 setvar(name, NULL, VSTRFIXED);
9008 vp = *vpp; /* the new variable */
9009 lvp->flags = VUNSET;
9010 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009011 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009012 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009013 /* make sure neither "struct var" nor string gets freed
9014 * during (un)setting:
9015 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009016 vp->flags |= VSTRFIXED|VTEXTFIXED;
9017 if (eq)
9018 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009019 else
9020 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009021 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009022 }
9023 }
9024 lvp->vp = vp;
9025 lvp->next = localvars;
9026 localvars = lvp;
9027 INT_ON;
9028}
9029
9030/*
9031 * The "local" command.
9032 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009033static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009034localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009035{
9036 char *name;
9037
9038 argv = argptr;
9039 while ((name = *argv++) != NULL) {
9040 mklocal(name);
9041 }
9042 return 0;
9043}
9044
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009045static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009046falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009047{
9048 return 1;
9049}
9050
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009051static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009052truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009053{
9054 return 0;
9055}
9056
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009057static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009058execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009059{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009060 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009061 iflag = 0; /* exit on error */
9062 mflag = 0;
9063 optschanged();
9064 shellexec(argv + 1, pathval(), 0);
9065 }
9066 return 0;
9067}
9068
9069/*
9070 * The return command.
9071 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009072static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009073returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009074{
9075 /*
9076 * If called outside a function, do what ksh does;
9077 * skip the rest of the file.
9078 */
9079 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9080 return argv[1] ? number(argv[1]) : exitstatus;
9081}
9082
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009083/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009084static int breakcmd(int, char **) FAST_FUNC;
9085static int dotcmd(int, char **) FAST_FUNC;
9086static int evalcmd(int, char **) FAST_FUNC;
9087static int exitcmd(int, char **) FAST_FUNC;
9088static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009089#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009090static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009091#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009092#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009093static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009094#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009095#if MAX_HISTORY
9096static int historycmd(int, char **) FAST_FUNC;
9097#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009098#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009099static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009100#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009101static int readcmd(int, char **) FAST_FUNC;
9102static int setcmd(int, char **) FAST_FUNC;
9103static int shiftcmd(int, char **) FAST_FUNC;
9104static int timescmd(int, char **) FAST_FUNC;
9105static int trapcmd(int, char **) FAST_FUNC;
9106static int umaskcmd(int, char **) FAST_FUNC;
9107static int unsetcmd(int, char **) FAST_FUNC;
9108static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009109
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009110#define BUILTIN_NOSPEC "0"
9111#define BUILTIN_SPECIAL "1"
9112#define BUILTIN_REGULAR "2"
9113#define BUILTIN_SPEC_REG "3"
9114#define BUILTIN_ASSIGN "4"
9115#define BUILTIN_SPEC_ASSG "5"
9116#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009117#define BUILTIN_SPEC_REG_ASSG "7"
9118
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009119/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009120#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009121static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009122#endif
9123#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009124static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009125#endif
9126#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009127static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009128#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009129
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009130/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009131static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009132 { BUILTIN_SPEC_REG "." , dotcmd },
9133 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009134#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009135 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009136#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009137 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009138#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009139#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009140#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009141 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009142#endif
9143#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009144 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009145#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009146 { BUILTIN_SPEC_REG "break" , breakcmd },
9147 { BUILTIN_REGULAR "cd" , cdcmd },
9148 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009149#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009150 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009151#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009152 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009153#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009154 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009155#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009156 { BUILTIN_SPEC_REG "eval" , evalcmd },
9157 { BUILTIN_SPEC_REG "exec" , execcmd },
9158 { BUILTIN_SPEC_REG "exit" , exitcmd },
9159 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9160 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009161#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009162 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009163#endif
9164#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009165 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009166#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009167 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009168#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009169 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009170#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009171#if MAX_HISTORY
9172 { BUILTIN_NOSPEC "history" , historycmd },
9173#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009174#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009175 { BUILTIN_REGULAR "jobs" , jobscmd },
9176 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009177#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009178#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009179 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009180#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009181 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009182#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009183 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009184#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009185 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9186 { BUILTIN_REGULAR "read" , readcmd },
9187 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9188 { BUILTIN_SPEC_REG "return" , returncmd },
9189 { BUILTIN_SPEC_REG "set" , setcmd },
9190 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009191#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009192 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009193#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009194#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009195 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009196#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009197 { BUILTIN_SPEC_REG "times" , timescmd },
9198 { BUILTIN_SPEC_REG "trap" , trapcmd },
9199 { BUILTIN_REGULAR "true" , truecmd },
9200 { BUILTIN_NOSPEC "type" , typecmd },
9201 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9202 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009203#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009204 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009205#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009206 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9207 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009208};
9209
Denis Vlasenko80591b02008-03-25 07:49:43 +00009210/* Should match the above table! */
9211#define COMMANDCMD (builtintab + \
9212 2 + \
9213 1 * ENABLE_ASH_BUILTIN_TEST + \
9214 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9215 1 * ENABLE_ASH_ALIAS + \
9216 1 * ENABLE_ASH_JOB_CONTROL + \
9217 3)
9218#define EXECCMD (builtintab + \
9219 2 + \
9220 1 * ENABLE_ASH_BUILTIN_TEST + \
9221 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9222 1 * ENABLE_ASH_ALIAS + \
9223 1 * ENABLE_ASH_JOB_CONTROL + \
9224 3 + \
9225 1 * ENABLE_ASH_CMDCMD + \
9226 1 + \
9227 ENABLE_ASH_BUILTIN_ECHO + \
9228 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009229
9230/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009231 * Search the table of builtin commands.
9232 */
9233static struct builtincmd *
9234find_builtin(const char *name)
9235{
9236 struct builtincmd *bp;
9237
9238 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009239 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009240 pstrcmp
9241 );
9242 return bp;
9243}
9244
9245/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009246 * Execute a simple command.
9247 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009248static int
9249isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009250{
9251 const char *q = endofname(p);
9252 if (p == q)
9253 return 0;
9254 return *q == '=';
9255}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009256static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009257bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009258{
9259 /* Preserve exitstatus of a previous possible redirection
9260 * as POSIX mandates */
9261 return back_exitstatus;
9262}
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02009263static void
Eric Andersenc470f442003-07-28 09:56:35 +00009264evalcommand(union node *cmd, int flags)
9265{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009266 static const struct builtincmd null_bltin = {
9267 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009268 };
Eric Andersenc470f442003-07-28 09:56:35 +00009269 struct stackmark smark;
9270 union node *argp;
9271 struct arglist arglist;
9272 struct arglist varlist;
9273 char **argv;
9274 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009275 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009276 struct cmdentry cmdentry;
9277 struct job *jp;
9278 char *lastarg;
9279 const char *path;
9280 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009281 int status;
9282 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009283 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009284 smallint cmd_is_exec;
9285 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009286
9287 /* First expand the arguments. */
9288 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9289 setstackmark(&smark);
9290 back_exitstatus = 0;
9291
9292 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009293 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009294 varlist.lastp = &varlist.list;
9295 *varlist.lastp = NULL;
9296 arglist.lastp = &arglist.list;
9297 *arglist.lastp = NULL;
9298
9299 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009300 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009301 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9302 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9303 }
9304
Eric Andersenc470f442003-07-28 09:56:35 +00009305 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9306 struct strlist **spp;
9307
9308 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009309 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009310 expandarg(argp, &arglist, EXP_VARTILDE);
9311 else
9312 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9313
Eric Andersenc470f442003-07-28 09:56:35 +00009314 for (sp = *spp; sp; sp = sp->next)
9315 argc++;
9316 }
9317
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009318 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009319 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009320 TRACE(("evalcommand arg: %s\n", sp->text));
9321 *nargv++ = sp->text;
9322 }
9323 *nargv = NULL;
9324
9325 lastarg = NULL;
9326 if (iflag && funcnest == 0 && argc > 0)
9327 lastarg = nargv[-1];
9328
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009329 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009330 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009331 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009332
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009333 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009334 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9335 struct strlist **spp;
9336 char *p;
9337
9338 spp = varlist.lastp;
9339 expandarg(argp, &varlist, EXP_VARTILDE);
9340
9341 /*
9342 * Modify the command lookup path, if a PATH= assignment
9343 * is present
9344 */
9345 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009346 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009347 path = p;
9348 }
9349
9350 /* Print the command if xflag is set. */
9351 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009352 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009353 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009354
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009355 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009356 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009357 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009358 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009359 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009360 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009361 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009362 }
9363 sp = arglist.list;
9364 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009365 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009366 }
9367
9368 cmd_is_exec = 0;
9369 spclbltin = -1;
9370
9371 /* Now locate the command. */
9372 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009373 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009374#if ENABLE_ASH_CMDCMD
9375 const char *oldpath = path + 5;
9376#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009377 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009378 for (;;) {
9379 find_command(argv[0], &cmdentry, cmd_flag, path);
9380 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009381 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009382 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009383 goto bail;
9384 }
9385
9386 /* implement bltin and command here */
9387 if (cmdentry.cmdtype != CMDBUILTIN)
9388 break;
9389 if (spclbltin < 0)
9390 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9391 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009392 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009393#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009394 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009395 path = oldpath;
9396 nargv = parse_command_args(argv, &path);
9397 if (!nargv)
9398 break;
9399 argc -= nargv - argv;
9400 argv = nargv;
9401 cmd_flag |= DO_NOFUNC;
9402 } else
9403#endif
9404 break;
9405 }
9406 }
9407
9408 if (status) {
9409 /* We have a redirection error. */
9410 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009411 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009412 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009413 exitstatus = status;
9414 goto out;
9415 }
9416
9417 /* Execute the command. */
9418 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009419 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009420
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009421#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009422/* (1) BUG: if variables are set, we need to fork, or save/restore them
9423 * around run_nofork_applet() call.
9424 * (2) Should this check also be done in forkshell()?
9425 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9426 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009427 /* find_command() encodes applet_no as (-2 - applet_no) */
9428 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009429 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009430 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009431 /* run <applet>_main() */
9432 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009433 break;
9434 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009435#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009436 /* Can we avoid forking off? For example, very last command
9437 * in a script or a subshell does not need forking,
9438 * we can just exec it.
9439 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009440 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009441 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009442 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009443 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009444 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009445 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009446 exitstatus = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009447 INT_ON;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009448 TRACE(("forked child exited with %d\n", exitstatus));
Eric Andersenc470f442003-07-28 09:56:35 +00009449 break;
9450 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009451 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009452 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009453 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009454 }
9455 listsetvar(varlist.list, VEXPORT|VSTACK);
9456 shellexec(argv, path, cmdentry.u.index);
9457 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009458 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009459 case CMDBUILTIN:
9460 cmdenviron = varlist.list;
9461 if (cmdenviron) {
9462 struct strlist *list = cmdenviron;
9463 int i = VNOSET;
9464 if (spclbltin > 0 || argc == 0) {
9465 i = 0;
9466 if (cmd_is_exec && argc > 1)
9467 i = VEXPORT;
9468 }
9469 listsetvar(list, i);
9470 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009471 /* Tight loop with builtins only:
9472 * "while kill -0 $child; do true; done"
9473 * will never exit even if $child died, unless we do this
9474 * to reap the zombie and make kill detect that it's gone: */
9475 dowait(DOWAIT_NONBLOCK, NULL);
9476
Eric Andersenc470f442003-07-28 09:56:35 +00009477 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9478 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009479 int i = exception_type;
Eric Andersenc470f442003-07-28 09:56:35 +00009480 if (i == EXEXIT)
9481 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009482 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009483 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009484 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009485 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009486 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009487 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009488 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009489 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009490 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009491 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009492 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009493 }
9494 break;
9495
9496 case CMDFUNCTION:
9497 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009498 /* See above for the rationale */
9499 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009500 if (evalfun(cmdentry.u.func, argc, argv, flags))
9501 goto raise;
9502 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009503
9504 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009505
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009506 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009507 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009508 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009509 /* dsl: I think this is intended to be used to support
9510 * '_' in 'vi' command mode during line editing...
9511 * However I implemented that within libedit itself.
9512 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009513 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009514 }
Eric Andersenc470f442003-07-28 09:56:35 +00009515 popstackmark(&smark);
9516}
9517
9518static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009519evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9520{
Eric Andersenc470f442003-07-28 09:56:35 +00009521 char *volatile savecmdname;
9522 struct jmploc *volatile savehandler;
9523 struct jmploc jmploc;
9524 int i;
9525
9526 savecmdname = commandname;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009527 i = setjmp(jmploc.loc);
9528 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009529 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009530 savehandler = exception_handler;
9531 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009532 commandname = argv[0];
9533 argptr = argv + 1;
9534 optptr = NULL; /* initialize nextopt */
9535 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009536 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009537 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009538 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009539 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009540 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009541 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009542
9543 return i;
9544}
9545
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009546static int
9547goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009548{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009549 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009550}
9551
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009552
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009553/*
9554 * Search for a command. This is called before we fork so that the
9555 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009556 * the child. The check for "goodname" is an overly conservative
9557 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009558 */
Eric Andersenc470f442003-07-28 09:56:35 +00009559static void
9560prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009561{
9562 struct cmdentry entry;
9563
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009564 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9565 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009566}
9567
Eric Andersencb57d552001-06-28 07:25:16 +00009568
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009569/* ============ Builtin commands
9570 *
9571 * Builtin commands whose functions are closely tied to evaluation
9572 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009573 */
9574
9575/*
Eric Andersencb57d552001-06-28 07:25:16 +00009576 * Handle break and continue commands. Break, continue, and return are
9577 * all handled by setting the evalskip flag. The evaluation routines
9578 * above all check this flag, and if it is set they start skipping
9579 * commands rather than executing them. The variable skipcount is
9580 * the number of loops to break/continue, or the number of function
9581 * levels to return. (The latter is always 1.) It should probably
9582 * be an error to break out of more loops than exist, but it isn't
9583 * in the standard shell so we don't make it one here.
9584 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009585static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009586breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009587{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009588 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009589
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009590 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009591 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009592 if (n > loopnest)
9593 n = loopnest;
9594 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009595 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009596 skipcount = n;
9597 }
9598 return 0;
9599}
9600
Eric Andersenc470f442003-07-28 09:56:35 +00009601
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009602/* ============ input.c
9603 *
Eric Andersen90898442003-08-06 11:20:52 +00009604 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009605 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009606
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009607enum {
9608 INPUT_PUSH_FILE = 1,
9609 INPUT_NOFILE_OK = 2,
9610};
Eric Andersencb57d552001-06-28 07:25:16 +00009611
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009612static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009613/* values of checkkwd variable */
9614#define CHKALIAS 0x1
9615#define CHKKWD 0x2
9616#define CHKNL 0x4
9617
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009618/*
9619 * Push a string back onto the input at this current parsefile level.
9620 * We handle aliases this way.
9621 */
9622#if !ENABLE_ASH_ALIAS
9623#define pushstring(s, ap) pushstring(s)
9624#endif
9625static void
9626pushstring(char *s, struct alias *ap)
9627{
9628 struct strpush *sp;
9629 int len;
9630
9631 len = strlen(s);
9632 INT_OFF;
9633 if (g_parsefile->strpush) {
9634 sp = ckzalloc(sizeof(*sp));
9635 sp->prev = g_parsefile->strpush;
9636 } else {
9637 sp = &(g_parsefile->basestrpush);
9638 }
9639 g_parsefile->strpush = sp;
9640 sp->prev_string = g_parsefile->next_to_pgetc;
9641 sp->prev_left_in_line = g_parsefile->left_in_line;
9642#if ENABLE_ASH_ALIAS
9643 sp->ap = ap;
9644 if (ap) {
9645 ap->flag |= ALIASINUSE;
9646 sp->string = s;
9647 }
9648#endif
9649 g_parsefile->next_to_pgetc = s;
9650 g_parsefile->left_in_line = len;
9651 INT_ON;
9652}
9653
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009654static void
9655popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009656{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009657 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009658
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009659 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009660#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009661 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009662 if (g_parsefile->next_to_pgetc[-1] == ' '
9663 || g_parsefile->next_to_pgetc[-1] == '\t'
9664 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009665 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009666 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009667 if (sp->string != sp->ap->val) {
9668 free(sp->string);
9669 }
9670 sp->ap->flag &= ~ALIASINUSE;
9671 if (sp->ap->flag & ALIASDEAD) {
9672 unalias(sp->ap->name);
9673 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009674 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009675#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009676 g_parsefile->next_to_pgetc = sp->prev_string;
9677 g_parsefile->left_in_line = sp->prev_left_in_line;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009678 g_parsefile->strpush = sp->prev;
9679 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009680 free(sp);
9681 INT_ON;
9682}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009683
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009684//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9685//it peeks whether it is &>, and then pushes back both chars.
9686//This function needs to save last *next_to_pgetc to buf[0]
9687//to make two pungetc() reliable. Currently,
9688// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009689static int
9690preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009691{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009692 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009693 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009694
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009695 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009696#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009697 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009698 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Denys Vlasenko80542ba2011-05-08 21:23:43 +02009699 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009700 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009701 int timeout = -1;
9702# if ENABLE_ASH_IDLE_TIMEOUT
9703 if (iflag) {
9704 const char *tmout_var = lookupvar("TMOUT");
9705 if (tmout_var) {
9706 timeout = atoi(tmout_var) * 1000;
9707 if (timeout <= 0)
9708 timeout = -1;
9709 }
9710 }
9711# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009712# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009713 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009714# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009715 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009716 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009717 if (nr == 0) {
9718 /* Ctrl+C pressed */
9719 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009720 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009721 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009722 raise(SIGINT);
9723 return 1;
9724 }
Eric Andersenc470f442003-07-28 09:56:35 +00009725 goto retry;
9726 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009727 if (nr < 0) {
9728 if (errno == 0) {
9729 /* Ctrl+D pressed */
9730 nr = 0;
9731 }
9732# if ENABLE_ASH_IDLE_TIMEOUT
9733 else if (errno == EAGAIN && timeout > 0) {
9734 printf("\007timed out waiting for input: auto-logout\n");
9735 exitshell();
9736 }
9737# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009738 }
Eric Andersencb57d552001-06-28 07:25:16 +00009739 }
9740#else
Denys Vlasenko80542ba2011-05-08 21:23:43 +02009741 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009742#endif
9743
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009744#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009745 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009746 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009747 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009748 if (flags >= 0 && (flags & O_NONBLOCK)) {
9749 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009750 if (fcntl(0, F_SETFL, flags) >= 0) {
9751 out2str("sh: turning off NDELAY mode\n");
9752 goto retry;
9753 }
9754 }
9755 }
9756 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009757#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009758 return nr;
9759}
9760
9761/*
9762 * Refill the input buffer and return the next input character:
9763 *
9764 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009765 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9766 * or we are reading from a string so we can't refill the buffer,
9767 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009768 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009769 * 4) Process input up to the next newline, deleting nul characters.
9770 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009771//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9772#define pgetc_debug(...) ((void)0)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009773static int
Eric Andersenc470f442003-07-28 09:56:35 +00009774preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009775{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009776 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009777 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009778
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009779 while (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009780#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009781 if (g_parsefile->left_in_line == -1
9782 && g_parsefile->strpush->ap
9783 && g_parsefile->next_to_pgetc[-1] != ' '
9784 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009785 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009786 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009787 return PEOA;
9788 }
Eric Andersen2870d962001-07-02 17:27:21 +00009789#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009790 popstring();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009791 /* try "pgetc" now: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009792 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9793 g_parsefile->left_in_line,
9794 g_parsefile->next_to_pgetc,
9795 g_parsefile->next_to_pgetc);
9796 if (--g_parsefile->left_in_line >= 0)
9797 return (unsigned char)(*g_parsefile->next_to_pgetc++);
Eric Andersencb57d552001-06-28 07:25:16 +00009798 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009799 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009800 * "pgetc" needs refilling.
9801 */
9802
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009803 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009804 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009805 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009806 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009807 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009808 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009809 /* even in failure keep left_in_line and next_to_pgetc
9810 * in lock step, for correct multi-layer pungetc.
9811 * left_in_line was decremented before preadbuffer(),
9812 * must inc next_to_pgetc: */
9813 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009814 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009815 }
Eric Andersencb57d552001-06-28 07:25:16 +00009816
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009817 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009818 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009819 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009820 again:
9821 more = preadfd();
9822 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009823 /* don't try reading again */
9824 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009825 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009826 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009827 return PEOF;
9828 }
9829 }
9830
Denis Vlasenko727752d2008-11-28 03:41:47 +00009831 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009832 * Set g_parsefile->left_in_line
9833 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009834 * NUL chars are deleted.
9835 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009836 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009837 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009838 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009839
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009840 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009841
Denis Vlasenko727752d2008-11-28 03:41:47 +00009842 c = *q;
9843 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009844 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009845 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009846 q++;
9847 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009848 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009849 break;
9850 }
Eric Andersencb57d552001-06-28 07:25:16 +00009851 }
9852
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009853 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009854 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9855 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009856 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009857 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009858 }
9859 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009860 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009861
Eric Andersencb57d552001-06-28 07:25:16 +00009862 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009863 char save = *q;
9864 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009865 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009866 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009867 }
9868
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009869 pgetc_debug("preadbuffer at %d:%p'%s'",
9870 g_parsefile->left_in_line,
9871 g_parsefile->next_to_pgetc,
9872 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009873 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009874}
9875
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009876#define pgetc_as_macro() \
9877 (--g_parsefile->left_in_line >= 0 \
Denys Vlasenkocd716832009-11-28 22:14:02 +01009878 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009879 : preadbuffer() \
9880 )
Denis Vlasenko727752d2008-11-28 03:41:47 +00009881
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009882static int
9883pgetc(void)
9884{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009885 pgetc_debug("pgetc_fast at %d:%p'%s'",
9886 g_parsefile->left_in_line,
9887 g_parsefile->next_to_pgetc,
9888 g_parsefile->next_to_pgetc);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009889 return pgetc_as_macro();
9890}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009891
9892#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009893# define pgetc_fast() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009894#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009895# define pgetc_fast() pgetc_as_macro()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009896#endif
9897
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009898#if ENABLE_ASH_ALIAS
9899static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009900pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009901{
9902 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009903 do {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009904 pgetc_debug("pgetc_fast at %d:%p'%s'",
9905 g_parsefile->left_in_line,
9906 g_parsefile->next_to_pgetc,
9907 g_parsefile->next_to_pgetc);
Denis Vlasenko834dee72008-10-07 09:18:30 +00009908 c = pgetc_fast();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009909 } while (c == PEOA);
9910 return c;
9911}
9912#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009913# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009914#endif
9915
9916/*
9917 * Read a line from the script.
9918 */
9919static char *
9920pfgets(char *line, int len)
9921{
9922 char *p = line;
9923 int nleft = len;
9924 int c;
9925
9926 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009927 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009928 if (c == PEOF) {
9929 if (p == line)
9930 return NULL;
9931 break;
9932 }
9933 *p++ = c;
9934 if (c == '\n')
9935 break;
9936 }
9937 *p = '\0';
9938 return line;
9939}
9940
Eric Andersenc470f442003-07-28 09:56:35 +00009941/*
9942 * Undo the last call to pgetc. Only one character may be pushed back.
9943 * PEOF may be pushed back.
9944 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009945static void
Eric Andersenc470f442003-07-28 09:56:35 +00009946pungetc(void)
9947{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009948 g_parsefile->left_in_line++;
9949 g_parsefile->next_to_pgetc--;
9950 pgetc_debug("pushed back to %d:%p'%s'",
9951 g_parsefile->left_in_line,
9952 g_parsefile->next_to_pgetc,
9953 g_parsefile->next_to_pgetc);
Eric Andersencb57d552001-06-28 07:25:16 +00009954}
9955
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009956/*
9957 * To handle the "." command, a stack of input files is used. Pushfile
9958 * adds a new entry to the stack and popfile restores the previous level.
9959 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009960static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009961pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009962{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009963 struct parsefile *pf;
9964
Denis Vlasenko597906c2008-02-20 16:38:54 +00009965 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009966 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009967 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +00009968 /*pf->strpush = NULL; - ckzalloc did it */
9969 /*pf->basestrpush.prev = NULL;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009970 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009971}
9972
9973static void
9974popfile(void)
9975{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009976 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +00009977
Denis Vlasenkob012b102007-02-19 22:43:01 +00009978 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009979 if (pf->pf_fd >= 0)
9980 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +00009981 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009982 while (pf->strpush)
9983 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009984 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009985 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009986 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009987}
9988
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009989/*
9990 * Return to top level.
9991 */
9992static void
9993popallfiles(void)
9994{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009995 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009996 popfile();
9997}
9998
9999/*
10000 * Close the file(s) that the shell is reading commands from. Called
10001 * after a fork is done.
10002 */
10003static void
10004closescript(void)
10005{
10006 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010007 if (g_parsefile->pf_fd > 0) {
10008 close(g_parsefile->pf_fd);
10009 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010010 }
10011}
10012
10013/*
10014 * Like setinputfile, but takes an open file descriptor. Call this with
10015 * interrupts off.
10016 */
10017static void
10018setinputfd(int fd, int push)
10019{
Denis Vlasenko96e1b382007-09-30 23:50:48 +000010020 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010021 if (push) {
10022 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010023 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010024 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010025 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010026 if (g_parsefile->buf == NULL)
10027 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010028 g_parsefile->left_in_buffer = 0;
10029 g_parsefile->left_in_line = 0;
10030 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010031}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010032
Eric Andersenc470f442003-07-28 09:56:35 +000010033/*
10034 * Set the input to take input from a file. If push is set, push the
10035 * old input onto the stack first.
10036 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010037static int
10038setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010039{
10040 int fd;
10041 int fd2;
10042
Denis Vlasenkob012b102007-02-19 22:43:01 +000010043 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010044 fd = open(fname, O_RDONLY);
10045 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010046 if (flags & INPUT_NOFILE_OK)
10047 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010048 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010049 }
Eric Andersenc470f442003-07-28 09:56:35 +000010050 if (fd < 10) {
10051 fd2 = copyfd(fd, 10);
10052 close(fd);
10053 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010054 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010055 fd = fd2;
10056 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010057 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010058 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010059 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010060 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010061}
10062
Eric Andersencb57d552001-06-28 07:25:16 +000010063/*
10064 * Like setinputfile, but takes input from a string.
10065 */
Eric Andersenc470f442003-07-28 09:56:35 +000010066static void
10067setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010068{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010069 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010070 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010071 g_parsefile->next_to_pgetc = string;
10072 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010073 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010074 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010075 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010076}
10077
10078
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010079/* ============ mail.c
10080 *
10081 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010082 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010083
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010084#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010085
Eric Andersencb57d552001-06-28 07:25:16 +000010086#define MAXMBOXES 10
10087
Eric Andersenc470f442003-07-28 09:56:35 +000010088/* times of mailboxes */
10089static time_t mailtime[MAXMBOXES];
10090/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010091static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010092
Eric Andersencb57d552001-06-28 07:25:16 +000010093/*
Eric Andersenc470f442003-07-28 09:56:35 +000010094 * Print appropriate message(s) if mail has arrived.
10095 * If mail_var_path_changed is set,
10096 * then the value of MAIL has mail_var_path_changed,
10097 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010098 */
Eric Andersenc470f442003-07-28 09:56:35 +000010099static void
10100chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010101{
Eric Andersencb57d552001-06-28 07:25:16 +000010102 const char *mpath;
10103 char *p;
10104 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +000010105 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +000010106 struct stackmark smark;
10107 struct stat statb;
10108
Eric Andersencb57d552001-06-28 07:25:16 +000010109 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010110 mpath = mpathset() ? mpathval() : mailval();
10111 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010112 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010113 if (p == NULL)
10114 break;
10115 if (*p == '\0')
10116 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010117 for (q = p; *q; q++)
10118 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010119#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010120 if (q[-1] != '/')
10121 abort();
10122#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010123 q[-1] = '\0'; /* delete trailing '/' */
10124 if (stat(p, &statb) < 0) {
10125 *mtp = 0;
10126 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010127 }
Eric Andersenc470f442003-07-28 09:56:35 +000010128 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
10129 fprintf(
Denys Vlasenkoea8b2522010-06-02 12:57:26 +020010130 stderr, "%s\n",
Eric Andersenc470f442003-07-28 09:56:35 +000010131 pathopt ? pathopt : "you have mail"
10132 );
10133 }
10134 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +000010135 }
Eric Andersenc470f442003-07-28 09:56:35 +000010136 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010137 popstackmark(&smark);
10138}
Eric Andersencb57d552001-06-28 07:25:16 +000010139
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010140static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010141changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010142{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010143 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010144}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010145
Denis Vlasenko131ae172007-02-18 13:00:19 +000010146#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010147
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010148
10149/* ============ ??? */
10150
Eric Andersencb57d552001-06-28 07:25:16 +000010151/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010152 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010153 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010154static void
10155setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010156{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010157 char **newparam;
10158 char **ap;
10159 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010160
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010161 for (nparam = 0; argv[nparam]; nparam++)
10162 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010163 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10164 while (*argv) {
10165 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010166 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010167 *ap = NULL;
10168 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010169 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010170 shellparam.nparam = nparam;
10171 shellparam.p = newparam;
10172#if ENABLE_ASH_GETOPTS
10173 shellparam.optind = 1;
10174 shellparam.optoff = -1;
10175#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010176}
10177
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010178/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010179 * Process shell options. The global variable argptr contains a pointer
10180 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010181 *
10182 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10183 * For a non-interactive shell, an error condition encountered
10184 * by a special built-in ... shall cause the shell to write a diagnostic message
10185 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010186 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010187 * ...
10188 * Utility syntax error (option or operand error) Shall exit
10189 * ...
10190 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10191 * we see that bash does not do that (set "finishes" with error code 1 instead,
10192 * and shell continues), and people rely on this behavior!
10193 * Testcase:
10194 * set -o barfoo 2>/dev/null
10195 * echo $?
10196 *
10197 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010198 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010199static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010200plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010201{
10202 int i;
10203
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010204 if (name) {
10205 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010206 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010207 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010208 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010209 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010210 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010211 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010212 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010213 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010214 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010215 if (val) {
10216 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10217 } else {
10218 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10219 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010220 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010221 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010222}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010223static void
10224setoption(int flag, int val)
10225{
10226 int i;
10227
10228 for (i = 0; i < NOPTS; i++) {
10229 if (optletters(i) == flag) {
10230 optlist[i] = val;
10231 return;
10232 }
10233 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010234 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010235 /* NOTREACHED */
10236}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010237static int
Eric Andersenc470f442003-07-28 09:56:35 +000010238options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010239{
10240 char *p;
10241 int val;
10242 int c;
10243
10244 if (cmdline)
10245 minusc = NULL;
10246 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010247 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010248 if (c != '-' && c != '+')
10249 break;
10250 argptr++;
10251 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010252 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010253 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010254 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010255 if (!cmdline) {
10256 /* "-" means turn off -x and -v */
10257 if (p[0] == '\0')
10258 xflag = vflag = 0;
10259 /* "--" means reset params */
10260 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010261 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010262 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010263 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010264 }
Eric Andersencb57d552001-06-28 07:25:16 +000010265 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010266 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010267 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010268 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010269 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010270 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010271 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010272 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010273 /* it already printed err message */
10274 return 1; /* error */
10275 }
Eric Andersencb57d552001-06-28 07:25:16 +000010276 if (*argptr)
10277 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010278 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10279 isloginsh = 1;
10280 /* bash does not accept +-login, we also won't */
10281 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010282 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010283 isloginsh = 1;
10284 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010285 } else {
10286 setoption(c, val);
10287 }
10288 }
10289 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010290 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010291}
10292
Eric Andersencb57d552001-06-28 07:25:16 +000010293/*
Eric Andersencb57d552001-06-28 07:25:16 +000010294 * The shift builtin command.
10295 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010296static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010297shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010298{
10299 int n;
10300 char **ap1, **ap2;
10301
10302 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010303 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010304 n = number(argv[1]);
10305 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010306 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010307 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010308 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010309 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010310 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010311 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010312 }
10313 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010314 while ((*ap2++ = *ap1++) != NULL)
10315 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010316#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010317 shellparam.optind = 1;
10318 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010319#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010320 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010321 return 0;
10322}
10323
Eric Andersencb57d552001-06-28 07:25:16 +000010324/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010325 * POSIX requires that 'set' (but not export or readonly) output the
10326 * variables in lexicographic order - by the locale's collating order (sigh).
10327 * Maybe we could keep them in an ordered balanced binary tree
10328 * instead of hashed lists.
10329 * For now just roll 'em through qsort for printing...
10330 */
10331static int
10332showvars(const char *sep_prefix, int on, int off)
10333{
10334 const char *sep;
10335 char **ep, **epend;
10336
10337 ep = listvars(on, off, &epend);
10338 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10339
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010340 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010341
10342 for (; ep < epend; ep++) {
10343 const char *p;
10344 const char *q;
10345
10346 p = strchrnul(*ep, '=');
10347 q = nullstr;
10348 if (*p)
10349 q = single_quote(++p);
10350 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10351 }
10352 return 0;
10353}
10354
10355/*
Eric Andersencb57d552001-06-28 07:25:16 +000010356 * The set command builtin.
10357 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010358static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010359setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010360{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010361 int retval;
10362
Denis Vlasenko68404f12008-03-17 09:00:54 +000010363 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010364 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010365
Denis Vlasenkob012b102007-02-19 22:43:01 +000010366 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010367 retval = options(/*cmdline:*/ 0);
10368 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010369 optschanged();
10370 if (*argptr != NULL) {
10371 setparam(argptr);
10372 }
Eric Andersencb57d552001-06-28 07:25:16 +000010373 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010374 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010375 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010376}
10377
Denis Vlasenko131ae172007-02-18 13:00:19 +000010378#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010379static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010380change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010381{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010382 uint32_t t;
10383
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010384 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010385 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010386 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010387 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010388 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010389 vrandom.flags &= ~VNOFUNC;
10390 } else {
10391 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010392 t = strtoul(value, NULL, 10);
10393 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010394 }
Eric Andersenef02f822004-03-11 13:34:24 +000010395}
Eric Andersen16767e22004-03-16 05:14:10 +000010396#endif
10397
Denis Vlasenko131ae172007-02-18 13:00:19 +000010398#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010399static int
Eric Andersenc470f442003-07-28 09:56:35 +000010400getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010401{
10402 char *p, *q;
10403 char c = '?';
10404 int done = 0;
10405 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +000010406 char s[12];
10407 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010408
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010409 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010410 return 1;
10411 optnext = optfirst + *param_optind - 1;
10412
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010413 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010414 p = NULL;
10415 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010416 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010417 if (p == NULL || *p == '\0') {
10418 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010419 p = *optnext;
10420 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010421 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010422 p = NULL;
10423 done = 1;
10424 goto out;
10425 }
10426 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010427 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010428 goto atend;
10429 }
10430
10431 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010432 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010433 if (*q == '\0') {
10434 if (optstr[0] == ':') {
10435 s[0] = c;
10436 s[1] = '\0';
10437 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010438 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010439 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010440 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010441 }
10442 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010443 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010444 }
10445 if (*++q == ':')
10446 q++;
10447 }
10448
10449 if (*++q == ':') {
10450 if (*p == '\0' && (p = *optnext) == NULL) {
10451 if (optstr[0] == ':') {
10452 s[0] = c;
10453 s[1] = '\0';
10454 err |= setvarsafe("OPTARG", s, 0);
10455 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010456 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010457 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010458 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010459 c = '?';
10460 }
Eric Andersenc470f442003-07-28 09:56:35 +000010461 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010462 }
10463
10464 if (p == *optnext)
10465 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010466 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010467 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010468 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010469 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010470 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010471 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010472 *param_optind = optnext - optfirst + 1;
10473 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +000010474 err |= setvarsafe("OPTIND", s, VNOFUNC);
10475 s[0] = c;
10476 s[1] = '\0';
10477 err |= setvarsafe(optvar, s, 0);
10478 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010479 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010480 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010481 flush_stdout_stderr();
10482 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010483 }
10484 return done;
10485}
Eric Andersenc470f442003-07-28 09:56:35 +000010486
10487/*
10488 * The getopts builtin. Shellparam.optnext points to the next argument
10489 * to be processed. Shellparam.optptr points to the next character to
10490 * be processed in the current argument. If shellparam.optnext is NULL,
10491 * then it's the first time getopts has been called.
10492 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010493static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010494getoptscmd(int argc, char **argv)
10495{
10496 char **optbase;
10497
10498 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010499 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010500 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010501 optbase = shellparam.p;
10502 if (shellparam.optind > shellparam.nparam + 1) {
10503 shellparam.optind = 1;
10504 shellparam.optoff = -1;
10505 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010506 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010507 optbase = &argv[3];
10508 if (shellparam.optind > argc - 2) {
10509 shellparam.optind = 1;
10510 shellparam.optoff = -1;
10511 }
10512 }
10513
10514 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010515 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010516}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010517#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010518
Eric Andersencb57d552001-06-28 07:25:16 +000010519
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010520/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010521
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010522struct heredoc {
10523 struct heredoc *next; /* next here document in list */
10524 union node *here; /* redirection node */
10525 char *eofmark; /* string indicating end of input */
10526 smallint striptabs; /* if set, strip leading tabs */
10527};
10528
10529static smallint tokpushback; /* last token pushed back */
10530static smallint parsebackquote; /* nonzero if we are inside backquotes */
10531static smallint quoteflag; /* set if (part of) last token was quoted */
10532static token_id_t lasttoken; /* last token read (integer id Txxx) */
10533static struct heredoc *heredoclist; /* list of here documents to read */
10534static char *wordtext; /* text of last word returned by readtoken */
10535static struct nodelist *backquotelist;
10536static union node *redirnode;
10537static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010538
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010539static const char *
10540tokname(char *buf, int tok)
10541{
10542 if (tok < TSEMI)
10543 return tokname_array[tok] + 1;
10544 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10545 return buf;
10546}
10547
10548/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010549 * Called when an unexpected token is read during the parse. The argument
10550 * is the token that is expected, or -1 if more than one type of token can
10551 * occur at this point.
10552 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010553static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010554static void
10555raise_error_unexpected_syntax(int token)
10556{
10557 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010558 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010559 int l;
10560
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010561 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010562 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010563 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010564 raise_error_syntax(msg);
10565 /* NOTREACHED */
10566}
Eric Andersencb57d552001-06-28 07:25:16 +000010567
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010568#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010569
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010570/* parsing is heavily cross-recursive, need these forward decls */
10571static union node *andor(void);
10572static union node *pipeline(void);
10573static union node *parse_command(void);
10574static void parseheredoc(void);
Denys Vlasenko7e661022015-02-05 21:00:17 +010010575static char nexttoken_ends_list(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010576static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010577
Eric Andersenc470f442003-07-28 09:56:35 +000010578static union node *
10579list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010580{
10581 union node *n1, *n2, *n3;
10582 int tok;
10583
Eric Andersenc470f442003-07-28 09:56:35 +000010584 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko7e661022015-02-05 21:00:17 +010010585 if (nlflag == 2 && nexttoken_ends_list())
Eric Andersencb57d552001-06-28 07:25:16 +000010586 return NULL;
10587 n1 = NULL;
10588 for (;;) {
10589 n2 = andor();
10590 tok = readtoken();
10591 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010592 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010593 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010594 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010595 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010596 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010597 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010598 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010599 n2 = n3;
10600 }
10601 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010602 }
10603 }
10604 if (n1 == NULL) {
10605 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010606 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010607 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010608 n3->type = NSEMI;
10609 n3->nbinary.ch1 = n1;
10610 n3->nbinary.ch2 = n2;
10611 n1 = n3;
10612 }
10613 switch (tok) {
10614 case TBACKGND:
10615 case TSEMI:
10616 tok = readtoken();
10617 /* fall through */
10618 case TNL:
10619 if (tok == TNL) {
10620 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +000010621 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +000010622 return n1;
10623 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010624 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010625 }
Eric Andersenc470f442003-07-28 09:56:35 +000010626 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denys Vlasenko7e661022015-02-05 21:00:17 +010010627 if (nexttoken_ends_list()) {
10628 /* Testcase: "<<EOF; then <W".
10629 * It used to segfault w/o this check:
10630 */
10631 if (heredoclist) {
10632 raise_error_unexpected_syntax(-1);
10633 }
Eric Andersencb57d552001-06-28 07:25:16 +000010634 return n1;
Denys Vlasenko7e661022015-02-05 21:00:17 +010010635 }
Eric Andersencb57d552001-06-28 07:25:16 +000010636 break;
10637 case TEOF:
10638 if (heredoclist)
10639 parseheredoc();
10640 else
Eric Andersenc470f442003-07-28 09:56:35 +000010641 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +000010642 return n1;
10643 default:
Eric Andersenc470f442003-07-28 09:56:35 +000010644 if (nlflag == 1)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010645 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010646 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010647 return n1;
10648 }
10649 }
10650}
10651
Eric Andersenc470f442003-07-28 09:56:35 +000010652static union node *
10653andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010654{
Eric Andersencb57d552001-06-28 07:25:16 +000010655 union node *n1, *n2, *n3;
10656 int t;
10657
Eric Andersencb57d552001-06-28 07:25:16 +000010658 n1 = pipeline();
10659 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010660 t = readtoken();
10661 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010662 t = NAND;
10663 } else if (t == TOR) {
10664 t = NOR;
10665 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010666 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010667 return n1;
10668 }
Eric Andersenc470f442003-07-28 09:56:35 +000010669 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010670 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010671 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010672 n3->type = t;
10673 n3->nbinary.ch1 = n1;
10674 n3->nbinary.ch2 = n2;
10675 n1 = n3;
10676 }
10677}
10678
Eric Andersenc470f442003-07-28 09:56:35 +000010679static union node *
10680pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010681{
Eric Andersencb57d552001-06-28 07:25:16 +000010682 union node *n1, *n2, *pipenode;
10683 struct nodelist *lp, *prev;
10684 int negate;
10685
10686 negate = 0;
10687 TRACE(("pipeline: entered\n"));
10688 if (readtoken() == TNOT) {
10689 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010690 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010691 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010692 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010693 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010694 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010695 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010696 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010697 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010698 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010699 pipenode->npipe.cmdlist = lp;
10700 lp->n = n1;
10701 do {
10702 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010703 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010704 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010705 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010706 prev->next = lp;
10707 } while (readtoken() == TPIPE);
10708 lp->next = NULL;
10709 n1 = pipenode;
10710 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010711 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010712 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010713 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010714 n2->type = NNOT;
10715 n2->nnot.com = n1;
10716 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010717 }
10718 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010719}
10720
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010721static union node *
10722makename(void)
10723{
10724 union node *n;
10725
Denis Vlasenko597906c2008-02-20 16:38:54 +000010726 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010727 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010728 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010729 n->narg.text = wordtext;
10730 n->narg.backquote = backquotelist;
10731 return n;
10732}
10733
10734static void
10735fixredir(union node *n, const char *text, int err)
10736{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010737 int fd;
10738
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010739 TRACE(("Fix redir %s %d\n", text, err));
10740 if (!err)
10741 n->ndup.vname = NULL;
10742
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010743 fd = bb_strtou(text, NULL, 10);
10744 if (!errno && fd >= 0)
10745 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010746 else if (LONE_DASH(text))
10747 n->ndup.dupfd = -1;
10748 else {
10749 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010750 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010751 n->ndup.vname = makename();
10752 }
10753}
10754
10755/*
10756 * Returns true if the text contains nothing to expand (no dollar signs
10757 * or backquotes).
10758 */
10759static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010760noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010761{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010762 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010763
Denys Vlasenkocd716832009-11-28 22:14:02 +010010764 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010765 if (c == CTLQUOTEMARK)
10766 continue;
10767 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010768 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010769 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010770 return 0;
10771 }
10772 return 1;
10773}
10774
10775static void
10776parsefname(void)
10777{
10778 union node *n = redirnode;
10779
10780 if (readtoken() != TWORD)
10781 raise_error_unexpected_syntax(-1);
10782 if (n->type == NHERE) {
10783 struct heredoc *here = heredoc;
10784 struct heredoc *p;
10785 int i;
10786
10787 if (quoteflag == 0)
10788 n->type = NXHERE;
10789 TRACE(("Here document %d\n", n->type));
10790 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010791 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010792 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010793 here->eofmark = wordtext;
10794 here->next = NULL;
10795 if (heredoclist == NULL)
10796 heredoclist = here;
10797 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010798 for (p = heredoclist; p->next; p = p->next)
10799 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010800 p->next = here;
10801 }
10802 } else if (n->type == NTOFD || n->type == NFROMFD) {
10803 fixredir(n, wordtext, 0);
10804 } else {
10805 n->nfile.fname = makename();
10806 }
10807}
Eric Andersencb57d552001-06-28 07:25:16 +000010808
Eric Andersenc470f442003-07-28 09:56:35 +000010809static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010810simplecmd(void)
10811{
10812 union node *args, **app;
10813 union node *n = NULL;
10814 union node *vars, **vpp;
10815 union node **rpp, *redir;
10816 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010817#if ENABLE_ASH_BASH_COMPAT
10818 smallint double_brackets_flag = 0;
10819#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010820
10821 args = NULL;
10822 app = &args;
10823 vars = NULL;
10824 vpp = &vars;
10825 redir = NULL;
10826 rpp = &redir;
10827
10828 savecheckkwd = CHKALIAS;
10829 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010830 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010831 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010832 t = readtoken();
10833 switch (t) {
10834#if ENABLE_ASH_BASH_COMPAT
10835 case TAND: /* "&&" */
10836 case TOR: /* "||" */
10837 if (!double_brackets_flag) {
10838 tokpushback = 1;
10839 goto out;
10840 }
10841 wordtext = (char *) (t == TAND ? "-a" : "-o");
10842#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010843 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010844 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010845 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010846 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010847 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010848#if ENABLE_ASH_BASH_COMPAT
10849 if (strcmp("[[", wordtext) == 0)
10850 double_brackets_flag = 1;
10851 else if (strcmp("]]", wordtext) == 0)
10852 double_brackets_flag = 0;
10853#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010854 n->narg.backquote = backquotelist;
10855 if (savecheckkwd && isassignment(wordtext)) {
10856 *vpp = n;
10857 vpp = &n->narg.next;
10858 } else {
10859 *app = n;
10860 app = &n->narg.next;
10861 savecheckkwd = 0;
10862 }
10863 break;
10864 case TREDIR:
10865 *rpp = n = redirnode;
10866 rpp = &n->nfile.next;
10867 parsefname(); /* read name of redirection file */
10868 break;
10869 case TLP:
10870 if (args && app == &args->narg.next
10871 && !vars && !redir
10872 ) {
10873 struct builtincmd *bcmd;
10874 const char *name;
10875
10876 /* We have a function */
10877 if (readtoken() != TRP)
10878 raise_error_unexpected_syntax(TRP);
10879 name = n->narg.text;
10880 if (!goodname(name)
10881 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10882 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010883 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010884 }
10885 n->type = NDEFUN;
10886 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10887 n->narg.next = parse_command();
10888 return n;
10889 }
10890 /* fall through */
10891 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010892 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010893 goto out;
10894 }
10895 }
10896 out:
10897 *app = NULL;
10898 *vpp = NULL;
10899 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010900 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010901 n->type = NCMD;
10902 n->ncmd.args = args;
10903 n->ncmd.assign = vars;
10904 n->ncmd.redirect = redir;
10905 return n;
10906}
10907
10908static union node *
10909parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010910{
Eric Andersencb57d552001-06-28 07:25:16 +000010911 union node *n1, *n2;
10912 union node *ap, **app;
10913 union node *cp, **cpp;
10914 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000010915 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000010916 int t;
10917
10918 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000010919 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000010920
Eric Andersencb57d552001-06-28 07:25:16 +000010921 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000010922 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010923 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000010924 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000010925 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010926 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010927 n1->type = NIF;
10928 n1->nif.test = list(0);
10929 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010930 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010931 n1->nif.ifpart = list(0);
10932 n2 = n1;
10933 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010934 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010935 n2 = n2->nif.elsepart;
10936 n2->type = NIF;
10937 n2->nif.test = list(0);
10938 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010939 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010940 n2->nif.ifpart = list(0);
10941 }
10942 if (lasttoken == TELSE)
10943 n2->nif.elsepart = list(0);
10944 else {
10945 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010946 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010947 }
Eric Andersenc470f442003-07-28 09:56:35 +000010948 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000010949 break;
10950 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010951 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000010952 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010953 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010954 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000010955 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010956 got = readtoken();
10957 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010958 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000010959 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010960 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010961 }
10962 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010963 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010964 break;
10965 }
10966 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010967 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000010968 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010969 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000010970 n1->type = NFOR;
10971 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +000010972 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010973 if (readtoken() == TIN) {
10974 app = &ap;
10975 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010976 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010977 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010978 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010979 n2->narg.text = wordtext;
10980 n2->narg.backquote = backquotelist;
10981 *app = n2;
10982 app = &n2->narg.next;
10983 }
10984 *app = NULL;
10985 n1->nfor.args = ap;
10986 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010987 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000010988 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010989 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010990 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010991 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010992 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010993 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000010994 n1->nfor.args = n2;
10995 /*
10996 * Newline or semicolon here is optional (but note
10997 * that the original Bourne shell only allowed NL).
10998 */
10999 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011000 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011001 }
Eric Andersenc470f442003-07-28 09:56:35 +000011002 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011003 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011004 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000011005 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011006 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000011007 break;
11008 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011009 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000011010 n1->type = NCASE;
11011 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011012 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011013 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011014 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011015 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011016 n2->narg.text = wordtext;
11017 n2->narg.backquote = backquotelist;
Eric Andersencb57d552001-06-28 07:25:16 +000011018 do {
Eric Andersenc470f442003-07-28 09:56:35 +000011019 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000011020 } while (readtoken() == TNL);
11021 if (lasttoken != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011022 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011023 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011024 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011025 checkkwd = CHKNL | CHKKWD;
11026 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011027 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011028 if (lasttoken == TLP)
11029 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011030 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011031 cp->type = NCLIST;
11032 app = &cp->nclist.pattern;
11033 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011034 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011035 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011036 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011037 ap->narg.text = wordtext;
11038 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011039 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011040 break;
11041 app = &ap->narg.next;
11042 readtoken();
11043 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011044 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011045 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011046 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011047 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011048
Eric Andersenc470f442003-07-28 09:56:35 +000011049 cpp = &cp->nclist.next;
11050
11051 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011052 t = readtoken();
11053 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011054 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011055 raise_error_unexpected_syntax(TENDCASE);
11056 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011057 }
Eric Andersenc470f442003-07-28 09:56:35 +000011058 }
Eric Andersencb57d552001-06-28 07:25:16 +000011059 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011060 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011061 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011062 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011063 n1->type = NSUBSHELL;
11064 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011065 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011066 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011067 break;
11068 case TBEGIN:
11069 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011070 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011071 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011072 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011073 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011074 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011075 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011076 }
11077
Eric Andersenc470f442003-07-28 09:56:35 +000011078 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011079 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011080
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011081 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011082 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011083 checkkwd = CHKKWD | CHKALIAS;
11084 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011085 while (readtoken() == TREDIR) {
11086 *rpp = n2 = redirnode;
11087 rpp = &n2->nfile.next;
11088 parsefname();
11089 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011090 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011091 *rpp = NULL;
11092 if (redir) {
11093 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011094 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011095 n2->type = NREDIR;
11096 n2->nredir.n = n1;
11097 n1 = n2;
11098 }
11099 n1->nredir.redirect = redir;
11100 }
Eric Andersencb57d552001-06-28 07:25:16 +000011101 return n1;
11102}
11103
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011104#if ENABLE_ASH_BASH_COMPAT
11105static int decode_dollar_squote(void)
11106{
11107 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11108 int c, cnt;
11109 char *p;
11110 char buf[4];
11111
11112 c = pgetc();
11113 p = strchr(C_escapes, c);
11114 if (p) {
11115 buf[0] = c;
11116 p = buf;
11117 cnt = 3;
11118 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11119 do {
11120 c = pgetc();
11121 *++p = c;
11122 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11123 pungetc();
11124 } else if (c == 'x') { /* \xHH */
11125 do {
11126 c = pgetc();
11127 *++p = c;
11128 } while (isxdigit(c) && --cnt);
11129 pungetc();
11130 if (cnt == 3) { /* \x but next char is "bad" */
11131 c = 'x';
11132 goto unrecognized;
11133 }
11134 } else { /* simple seq like \\ or \t */
11135 p++;
11136 }
11137 *p = '\0';
11138 p = buf;
11139 c = bb_process_escape_sequence((void*)&p);
11140 } else { /* unrecognized "\z": print both chars unless ' or " */
11141 if (c != '\'' && c != '"') {
11142 unrecognized:
11143 c |= 0x100; /* "please encode \, then me" */
11144 }
11145 }
11146 return c;
11147}
11148#endif
11149
Eric Andersencb57d552001-06-28 07:25:16 +000011150/*
11151 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11152 * is not NULL, read a here document. In the latter case, eofmark is the
11153 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011154 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011155 * is the first character of the input token or document.
11156 *
11157 * Because C does not have internal subroutines, I have simulated them
11158 * using goto's to implement the subroutine linkage. The following macros
11159 * will run code that appears at the end of readtoken1.
11160 */
Eric Andersen2870d962001-07-02 17:27:21 +000011161#define CHECKEND() {goto checkend; checkend_return:;}
11162#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11163#define PARSESUB() {goto parsesub; parsesub_return:;}
11164#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11165#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11166#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011167static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011168readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011169{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011170 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011171 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011172 char *out;
11173 int len;
11174 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011175 struct nodelist *bqlist;
11176 smallint quotef;
11177 smallint dblquote;
11178 smallint oldstyle;
11179 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011180#if ENABLE_ASH_EXPAND_PRMT
11181 smallint pssyntax; /* we are expanding a prompt string */
11182#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011183 int varnest; /* levels of variables expansion */
11184 int arinest; /* levels of arithmetic expansion */
11185 int parenlevel; /* levels of parens in arithmetic */
11186 int dqvarnest; /* levels of variables expansion within double quotes */
11187
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011188 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011189
Eric Andersencb57d552001-06-28 07:25:16 +000011190#if __GNUC__
11191 /* Avoid longjmp clobbering */
11192 (void) &out;
11193 (void) &quotef;
11194 (void) &dblquote;
11195 (void) &varnest;
11196 (void) &arinest;
11197 (void) &parenlevel;
11198 (void) &dqvarnest;
11199 (void) &oldstyle;
11200 (void) &prevsyntax;
11201 (void) &syntax;
11202#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011203 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011204 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011205 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011206 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011207#if ENABLE_ASH_EXPAND_PRMT
11208 pssyntax = (syntax == PSSYNTAX);
11209 if (pssyntax)
11210 syntax = DQSYNTAX;
11211#endif
11212 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011213 varnest = 0;
11214 arinest = 0;
11215 parenlevel = 0;
11216 dqvarnest = 0;
11217
11218 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011219 loop:
11220 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011221 CHECKEND(); /* set c to PEOF if at end of here document */
11222 for (;;) { /* until end of line or end of word */
11223 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11224 switch (SIT(c, syntax)) {
11225 case CNL: /* '\n' */
11226 if (syntax == BASESYNTAX)
11227 goto endword; /* exit outer loop */
11228 USTPUTC(c, out);
11229 g_parsefile->linno++;
11230 setprompt_if(doprompt, 2);
11231 c = pgetc();
11232 goto loop; /* continue outer loop */
11233 case CWORD:
11234 USTPUTC(c, out);
11235 break;
11236 case CCTL:
11237 if (eofmark == NULL || dblquote)
11238 USTPUTC(CTLESC, out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011239#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011240 if (c == '\\' && bash_dollar_squote) {
11241 c = decode_dollar_squote();
11242 if (c & 0x100) {
11243 USTPUTC('\\', out);
11244 c = (unsigned char)c;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011245 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011246 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011247#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011248 USTPUTC(c, out);
11249 break;
11250 case CBACK: /* backslash */
11251 c = pgetc_without_PEOA();
11252 if (c == PEOF) {
11253 USTPUTC(CTLESC, out);
11254 USTPUTC('\\', out);
11255 pungetc();
11256 } else if (c == '\n') {
11257 setprompt_if(doprompt, 2);
11258 } else {
11259#if ENABLE_ASH_EXPAND_PRMT
11260 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011261 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011262 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011263 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011264#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011265 /* Backslash is retained if we are in "str" and next char isn't special */
11266 if (dblquote
11267 && c != '\\'
11268 && c != '`'
11269 && c != '$'
11270 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011271 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011272 USTPUTC(CTLESC, out);
11273 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011274 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011275 if (SIT(c, SQSYNTAX) == CCTL)
11276 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011277 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011278 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011279 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011280 break;
11281 case CSQUOTE:
11282 syntax = SQSYNTAX;
11283 quotemark:
11284 if (eofmark == NULL) {
11285 USTPUTC(CTLQUOTEMARK, out);
11286 }
11287 break;
11288 case CDQUOTE:
11289 syntax = DQSYNTAX;
11290 dblquote = 1;
11291 goto quotemark;
11292 case CENDQUOTE:
11293 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11294 if (eofmark != NULL && arinest == 0
11295 && varnest == 0
11296 ) {
11297 USTPUTC(c, out);
11298 } else {
11299 if (dqvarnest == 0) {
11300 syntax = BASESYNTAX;
11301 dblquote = 0;
11302 }
11303 quotef = 1;
11304 goto quotemark;
11305 }
11306 break;
11307 case CVAR: /* '$' */
11308 PARSESUB(); /* parse substitution */
11309 break;
11310 case CENDVAR: /* '}' */
11311 if (varnest > 0) {
11312 varnest--;
11313 if (dqvarnest > 0) {
11314 dqvarnest--;
11315 }
11316 c = CTLENDVAR;
11317 }
11318 USTPUTC(c, out);
11319 break;
11320#if ENABLE_SH_MATH_SUPPORT
11321 case CLP: /* '(' in arithmetic */
11322 parenlevel++;
11323 USTPUTC(c, out);
11324 break;
11325 case CRP: /* ')' in arithmetic */
11326 if (parenlevel > 0) {
11327 parenlevel--;
11328 } else {
11329 if (pgetc() == ')') {
11330 if (--arinest == 0) {
11331 syntax = prevsyntax;
11332 dblquote = (syntax == DQSYNTAX);
11333 c = CTLENDARI;
11334 }
11335 } else {
11336 /*
11337 * unbalanced parens
11338 * (don't 2nd guess - no error)
11339 */
11340 pungetc();
11341 }
11342 }
11343 USTPUTC(c, out);
11344 break;
11345#endif
11346 case CBQUOTE: /* '`' */
11347 PARSEBACKQOLD();
11348 break;
11349 case CENDFILE:
11350 goto endword; /* exit outer loop */
11351 case CIGN:
11352 break;
11353 default:
11354 if (varnest == 0) {
11355#if ENABLE_ASH_BASH_COMPAT
11356 if (c == '&') {
11357 if (pgetc() == '>')
11358 c = 0x100 + '>'; /* flag &> */
11359 pungetc();
11360 }
11361#endif
11362 goto endword; /* exit outer loop */
11363 }
11364 IF_ASH_ALIAS(if (c != PEOA))
11365 USTPUTC(c, out);
11366 }
11367 c = pgetc_fast();
11368 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011369 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011370
Mike Frysinger98c52642009-04-02 10:02:37 +000011371#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011372 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011373 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011374#endif
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011375 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011376 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011377 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011378 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011379 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011380 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011381 }
11382 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011383 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011384 out = stackblock();
11385 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011386 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011387 && quotef == 0
11388 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011389 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011390 PARSEREDIR(); /* passed as params: out, c */
11391 lasttoken = TREDIR;
11392 return lasttoken;
11393 }
11394 /* else: non-number X seen, interpret it
11395 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011396 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011397 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011398 }
11399 quoteflag = quotef;
11400 backquotelist = bqlist;
11401 grabstackblock(len);
11402 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011403 lasttoken = TWORD;
11404 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011405/* end of readtoken routine */
11406
Eric Andersencb57d552001-06-28 07:25:16 +000011407/*
11408 * Check to see whether we are at the end of the here document. When this
11409 * is called, c is set to the first character of the next input line. If
11410 * we are at the end of the here document, this routine sets the c to PEOF.
11411 */
Eric Andersenc470f442003-07-28 09:56:35 +000011412checkend: {
11413 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011414#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011415 if (c == PEOA)
11416 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011417#endif
11418 if (striptabs) {
11419 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011420 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011421 }
Eric Andersenc470f442003-07-28 09:56:35 +000011422 }
11423 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011424 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011425 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011426
Eric Andersenc470f442003-07-28 09:56:35 +000011427 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011428 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11429 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011430 if (*p == '\n' && *q == '\0') {
11431 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011432 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011433 needprompt = doprompt;
11434 } else {
11435 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011436 }
11437 }
11438 }
11439 }
Eric Andersenc470f442003-07-28 09:56:35 +000011440 goto checkend_return;
11441}
Eric Andersencb57d552001-06-28 07:25:16 +000011442
Eric Andersencb57d552001-06-28 07:25:16 +000011443/*
11444 * Parse a redirection operator. The variable "out" points to a string
11445 * specifying the fd to be redirected. The variable "c" contains the
11446 * first character of the redirection operator.
11447 */
Eric Andersenc470f442003-07-28 09:56:35 +000011448parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011449 /* out is already checked to be a valid number or "" */
11450 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011451 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011452
Denis Vlasenko597906c2008-02-20 16:38:54 +000011453 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011454 if (c == '>') {
11455 np->nfile.fd = 1;
11456 c = pgetc();
11457 if (c == '>')
11458 np->type = NAPPEND;
11459 else if (c == '|')
11460 np->type = NCLOBBER;
11461 else if (c == '&')
11462 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011463 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011464 else {
11465 np->type = NTO;
11466 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011467 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011468 }
11469#if ENABLE_ASH_BASH_COMPAT
11470 else if (c == 0x100 + '>') { /* this flags &> redirection */
11471 np->nfile.fd = 1;
11472 pgetc(); /* this is '>', no need to check */
11473 np->type = NTO2;
11474 }
11475#endif
11476 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011477 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011478 c = pgetc();
11479 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011480 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011481 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011482 np = stzalloc(sizeof(struct nhere));
11483 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011484 }
11485 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011486 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011487 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011488 c = pgetc();
11489 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011490 heredoc->striptabs = 1;
11491 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011492 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011493 pungetc();
11494 }
11495 break;
11496
11497 case '&':
11498 np->type = NFROMFD;
11499 break;
11500
11501 case '>':
11502 np->type = NFROMTO;
11503 break;
11504
11505 default:
11506 np->type = NFROM;
11507 pungetc();
11508 break;
11509 }
Eric Andersencb57d552001-06-28 07:25:16 +000011510 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011511 if (fd >= 0)
11512 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011513 redirnode = np;
11514 goto parseredir_return;
11515}
Eric Andersencb57d552001-06-28 07:25:16 +000011516
Eric Andersencb57d552001-06-28 07:25:16 +000011517/*
11518 * Parse a substitution. At this point, we have read the dollar sign
11519 * and nothing else.
11520 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011521
11522/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11523 * (assuming ascii char codes, as the original implementation did) */
11524#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011525 (((unsigned)(c) - 33 < 32) \
11526 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011527parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011528 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011529 int typeloc;
11530 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011531
Eric Andersenc470f442003-07-28 09:56:35 +000011532 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011533 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011534 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011535 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011536#if ENABLE_ASH_BASH_COMPAT
11537 if (c == '\'')
11538 bash_dollar_squote = 1;
11539 else
11540#endif
11541 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011542 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011543 } else if (c == '(') {
11544 /* $(command) or $((arith)) */
Eric Andersenc470f442003-07-28 09:56:35 +000011545 if (pgetc() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011546#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011547 PARSEARITH();
11548#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011549 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011550#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011551 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011552 pungetc();
11553 PARSEBACKQNEW();
11554 }
11555 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011556 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011557 USTPUTC(CTLVAR, out);
11558 typeloc = out - (char *)stackblock();
11559 USTPUTC(VSNORMAL, out);
11560 subtype = VSNORMAL;
11561 if (c == '{') {
11562 c = pgetc();
11563 if (c == '#') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011564 c = pgetc();
11565 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011566 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011567 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011568 subtype = VSLENGTH; /* ${#VAR} */
11569 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011570 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011571 }
Eric Andersenc470f442003-07-28 09:56:35 +000011572 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011573 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011574 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011575 do {
11576 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011577 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011578 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011579 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011580 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011581 do {
11582 STPUTC(c, out);
11583 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011584 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011585 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011586 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011587 USTPUTC(c, out);
11588 c = pgetc();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011589 } else {
11590 badsub:
11591 raise_error_syntax("bad substitution");
11592 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011593 if (c != '}' && subtype == VSLENGTH) {
11594 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011595 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011596 }
Eric Andersencb57d552001-06-28 07:25:16 +000011597
Eric Andersenc470f442003-07-28 09:56:35 +000011598 STPUTC('=', out);
11599 flags = 0;
11600 if (subtype == 0) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011601 /* ${VAR...} but not $VAR or ${#VAR} */
11602 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011603 switch (c) {
11604 case ':':
Eric Andersenc470f442003-07-28 09:56:35 +000011605 c = pgetc();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011606#if ENABLE_ASH_BASH_COMPAT
11607 if (c == ':' || c == '$' || isdigit(c)) {
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011608//TODO: support more general format ${v:EXPR:EXPR},
11609// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011610 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011611 pungetc();
11612 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011613 }
11614#endif
11615 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011616 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011617 default: {
11618 static const char types[] ALIGN1 = "}-+?=";
11619 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011620 if (p == NULL)
11621 goto badsub;
11622 subtype = p - types + VSNORMAL;
11623 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011624 }
Eric Andersenc470f442003-07-28 09:56:35 +000011625 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011626 case '#': {
11627 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011628 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011629 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011630 if (c != cc)
11631 goto do_pungetc;
11632 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011633 break;
11634 }
11635#if ENABLE_ASH_BASH_COMPAT
11636 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011637 /* ${v/[/]pattern/repl} */
11638//TODO: encode pattern and repl separately.
11639// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011640 subtype = VSREPLACE;
11641 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011642 if (c != '/')
11643 goto do_pungetc;
11644 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011645 break;
11646#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011647 }
Eric Andersenc470f442003-07-28 09:56:35 +000011648 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011649 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011650 pungetc();
11651 }
11652 if (dblquote || arinest)
11653 flags |= VSQUOTE;
Denys Vlasenkocd716832009-11-28 22:14:02 +010011654 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011655 if (subtype != VSNORMAL) {
11656 varnest++;
11657 if (dblquote || arinest) {
11658 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011659 }
11660 }
11661 }
Eric Andersenc470f442003-07-28 09:56:35 +000011662 goto parsesub_return;
11663}
Eric Andersencb57d552001-06-28 07:25:16 +000011664
Eric Andersencb57d552001-06-28 07:25:16 +000011665/*
11666 * Called to parse command substitutions. Newstyle is set if the command
11667 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11668 * list of commands (passed by reference), and savelen is the number of
11669 * characters on the top of the stack which must be preserved.
11670 */
Eric Andersenc470f442003-07-28 09:56:35 +000011671parsebackq: {
11672 struct nodelist **nlpp;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011673 smallint savepbq;
Eric Andersenc470f442003-07-28 09:56:35 +000011674 union node *n;
11675 char *volatile str;
11676 struct jmploc jmploc;
11677 struct jmploc *volatile savehandler;
11678 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011679 smallint saveprompt = 0;
11680
Eric Andersencb57d552001-06-28 07:25:16 +000011681#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000011682 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000011683#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011684 savepbq = parsebackquote;
11685 if (setjmp(jmploc.loc)) {
Denis Vlasenko60818682007-09-28 22:07:23 +000011686 free(str);
Eric Andersenc470f442003-07-28 09:56:35 +000011687 parsebackquote = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011688 exception_handler = savehandler;
11689 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000011690 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011691 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011692 str = NULL;
11693 savelen = out - (char *)stackblock();
11694 if (savelen > 0) {
11695 str = ckmalloc(savelen);
11696 memcpy(str, stackblock(), savelen);
11697 }
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011698 savehandler = exception_handler;
11699 exception_handler = &jmploc;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011700 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000011701 if (oldstyle) {
11702 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011703 * treatment to some slashes, and then push the string and
11704 * reread it as input, interpreting it normally.
11705 */
Eric Andersenc470f442003-07-28 09:56:35 +000011706 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011707 size_t psavelen;
11708 char *pstr;
11709
Eric Andersenc470f442003-07-28 09:56:35 +000011710 STARTSTACKSTR(pout);
11711 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011712 int pc;
11713
11714 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011715 pc = pgetc();
11716 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011717 case '`':
11718 goto done;
11719
11720 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011721 pc = pgetc();
11722 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011723 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011724 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011725 /*
11726 * If eating a newline, avoid putting
11727 * the newline into the new character
11728 * stream (via the STPUTC after the
11729 * switch).
11730 */
11731 continue;
11732 }
11733 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011734 && (!dblquote || pc != '"')
11735 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011736 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011737 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011738 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011739 break;
11740 }
11741 /* fall through */
11742
11743 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011744 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011745 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011746 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011747
11748 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011749 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011750 needprompt = doprompt;
11751 break;
11752
11753 default:
11754 break;
11755 }
11756 STPUTC(pc, pout);
11757 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011758 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011759 STPUTC('\0', pout);
11760 psavelen = pout - (char *)stackblock();
11761 if (psavelen > 0) {
11762 pstr = grabstackstr(pout);
11763 setinputstring(pstr);
11764 }
11765 }
11766 nlpp = &bqlist;
11767 while (*nlpp)
11768 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011769 *nlpp = stzalloc(sizeof(**nlpp));
11770 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011771 parsebackquote = oldstyle;
11772
11773 if (oldstyle) {
11774 saveprompt = doprompt;
11775 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011776 }
11777
Eric Andersenc470f442003-07-28 09:56:35 +000011778 n = list(2);
11779
11780 if (oldstyle)
11781 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011782 else if (readtoken() != TRP)
11783 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011784
11785 (*nlpp)->n = n;
11786 if (oldstyle) {
11787 /*
11788 * Start reading from old file again, ignoring any pushed back
11789 * tokens left from the backquote parsing
11790 */
11791 popfile();
11792 tokpushback = 0;
11793 }
11794 while (stackblocksize() <= savelen)
11795 growstackblock();
11796 STARTSTACKSTR(out);
11797 if (str) {
11798 memcpy(out, str, savelen);
11799 STADJUST(savelen, out);
Denis Vlasenkob012b102007-02-19 22:43:01 +000011800 INT_OFF;
11801 free(str);
Eric Andersenc470f442003-07-28 09:56:35 +000011802 str = NULL;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011803 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000011804 }
11805 parsebackquote = savepbq;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011806 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000011807 if (arinest || dblquote)
11808 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11809 else
11810 USTPUTC(CTLBACKQ, out);
11811 if (oldstyle)
11812 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011813 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011814}
11815
Mike Frysinger98c52642009-04-02 10:02:37 +000011816#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011817/*
11818 * Parse an arithmetic expansion (indicate start of one and set state)
11819 */
Eric Andersenc470f442003-07-28 09:56:35 +000011820parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011821 if (++arinest == 1) {
11822 prevsyntax = syntax;
11823 syntax = ARISYNTAX;
11824 USTPUTC(CTLARI, out);
11825 if (dblquote)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011826 USTPUTC('"', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011827 else
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011828 USTPUTC(' ', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011829 } else {
11830 /*
11831 * we collapse embedded arithmetic expansion to
11832 * parenthesis, which should be equivalent
11833 */
11834 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011835 }
Eric Andersenc470f442003-07-28 09:56:35 +000011836 goto parsearith_return;
11837}
11838#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011839
Eric Andersenc470f442003-07-28 09:56:35 +000011840} /* end of readtoken */
11841
Eric Andersencb57d552001-06-28 07:25:16 +000011842/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011843 * Read the next input token.
11844 * If the token is a word, we set backquotelist to the list of cmds in
11845 * backquotes. We set quoteflag to true if any part of the word was
11846 * quoted.
11847 * If the token is TREDIR, then we set redirnode to a structure containing
11848 * the redirection.
11849 * In all cases, the variable startlinno is set to the number of the line
11850 * on which the token starts.
11851 *
11852 * [Change comment: here documents and internal procedures]
11853 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11854 * word parsing code into a separate routine. In this case, readtoken
11855 * doesn't need to have any internal procedures, but parseword does.
11856 * We could also make parseoperator in essence the main routine, and
11857 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011858 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011859#define NEW_xxreadtoken
11860#ifdef NEW_xxreadtoken
11861/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011862static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011863 '\n', '(', ')', /* singles */
11864 '&', '|', ';', /* doubles */
11865 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011866};
Eric Andersencb57d552001-06-28 07:25:16 +000011867
Denis Vlasenko834dee72008-10-07 09:18:30 +000011868#define xxreadtoken_singles 3
11869#define xxreadtoken_doubles 3
11870
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011871static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011872 TNL, TLP, TRP, /* only single occurrence allowed */
11873 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11874 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011875 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011876};
11877
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011878static int
11879xxreadtoken(void)
11880{
11881 int c;
11882
11883 if (tokpushback) {
11884 tokpushback = 0;
11885 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011886 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011887 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011888 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011889 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011890 c = pgetc_fast();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011891 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011892 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011893
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011894 if (c == '#') {
11895 while ((c = pgetc()) != '\n' && c != PEOF)
11896 continue;
11897 pungetc();
11898 } else if (c == '\\') {
11899 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011900 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011901 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011902 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011903 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011904 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011905 } else {
11906 const char *p;
11907
11908 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11909 if (c != PEOF) {
11910 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011911 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011912 needprompt = doprompt;
11913 }
11914
11915 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011916 if (p == NULL)
11917 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011918
Denis Vlasenko834dee72008-10-07 09:18:30 +000011919 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11920 int cc = pgetc();
11921 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011922 p += xxreadtoken_doubles + 1;
11923 } else {
11924 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011925#if ENABLE_ASH_BASH_COMPAT
11926 if (c == '&' && cc == '>') /* &> */
11927 break; /* return readtoken1(...) */
11928#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011929 }
11930 }
11931 }
11932 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11933 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011934 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011935 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011936
11937 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011938}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011939#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011940#define RETURN(token) return lasttoken = token
11941static int
11942xxreadtoken(void)
11943{
11944 int c;
11945
11946 if (tokpushback) {
11947 tokpushback = 0;
11948 return lasttoken;
11949 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011950 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011951 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011952 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011953 c = pgetc_fast();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011954 switch (c) {
11955 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011956 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011957 continue;
11958 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011959 while ((c = pgetc()) != '\n' && c != PEOF)
11960 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011961 pungetc();
11962 continue;
11963 case '\\':
11964 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011965 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011966 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011967 continue;
11968 }
11969 pungetc();
11970 goto breakloop;
11971 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011972 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011973 needprompt = doprompt;
11974 RETURN(TNL);
11975 case PEOF:
11976 RETURN(TEOF);
11977 case '&':
11978 if (pgetc() == '&')
11979 RETURN(TAND);
11980 pungetc();
11981 RETURN(TBACKGND);
11982 case '|':
11983 if (pgetc() == '|')
11984 RETURN(TOR);
11985 pungetc();
11986 RETURN(TPIPE);
11987 case ';':
11988 if (pgetc() == ';')
11989 RETURN(TENDCASE);
11990 pungetc();
11991 RETURN(TSEMI);
11992 case '(':
11993 RETURN(TLP);
11994 case ')':
11995 RETURN(TRP);
11996 default:
11997 goto breakloop;
11998 }
11999 }
12000 breakloop:
12001 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
12002#undef RETURN
12003}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000012004#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012005
12006static int
12007readtoken(void)
12008{
12009 int t;
12010#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012011 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012012#endif
12013
12014#if ENABLE_ASH_ALIAS
12015 top:
12016#endif
12017
12018 t = xxreadtoken();
12019
12020 /*
12021 * eat newlines
12022 */
12023 if (checkkwd & CHKNL) {
12024 while (t == TNL) {
12025 parseheredoc();
12026 t = xxreadtoken();
12027 }
12028 }
12029
12030 if (t != TWORD || quoteflag) {
12031 goto out;
12032 }
12033
12034 /*
12035 * check for keywords
12036 */
12037 if (checkkwd & CHKKWD) {
12038 const char *const *pp;
12039
12040 pp = findkwd(wordtext);
12041 if (pp) {
12042 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012043 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012044 goto out;
12045 }
12046 }
12047
12048 if (checkkwd & CHKALIAS) {
12049#if ENABLE_ASH_ALIAS
12050 struct alias *ap;
12051 ap = lookupalias(wordtext, 1);
12052 if (ap != NULL) {
12053 if (*ap->val) {
12054 pushstring(ap->val, ap);
12055 }
12056 goto top;
12057 }
12058#endif
12059 }
12060 out:
12061 checkkwd = 0;
12062#if DEBUG
12063 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012064 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012065 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012066 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012067#endif
12068 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012069}
12070
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012071static char
Denys Vlasenko7e661022015-02-05 21:00:17 +010012072nexttoken_ends_list(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012073{
12074 int t;
12075
12076 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012077 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012078 return tokname_array[t][0];
12079}
Eric Andersencb57d552001-06-28 07:25:16 +000012080
12081/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012082 * Read and parse a command. Returns NODE_EOF on end of file.
12083 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012084 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012085static union node *
12086parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012087{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012088 int t;
Eric Andersencb57d552001-06-28 07:25:16 +000012089
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012090 tokpushback = 0;
12091 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012092 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012093 needprompt = 0;
12094 t = readtoken();
12095 if (t == TEOF)
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012096 return NODE_EOF;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012097 if (t == TNL)
12098 return NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012099 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012100 return list(1);
12101}
12102
12103/*
12104 * Input any here documents.
12105 */
12106static void
12107parseheredoc(void)
12108{
12109 struct heredoc *here;
12110 union node *n;
12111
12112 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012113 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012114
12115 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012116 setprompt_if(needprompt, 2);
12117 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012118 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012119 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012120 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012121 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012122 n->narg.text = wordtext;
12123 n->narg.backquote = backquotelist;
12124 here->here->nhere.doc = n;
12125 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012126 }
Eric Andersencb57d552001-06-28 07:25:16 +000012127}
12128
12129
12130/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012131 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012132 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012133#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012134static const char *
12135expandstr(const char *ps)
12136{
12137 union node n;
12138
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012139 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12140 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012141 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012142 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012143 popfile();
12144
12145 n.narg.type = NARG;
12146 n.narg.next = NULL;
12147 n.narg.text = wordtext;
12148 n.narg.backquote = backquotelist;
12149
12150 expandarg(&n, NULL, 0);
12151 return stackblock();
12152}
12153#endif
12154
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012155/*
12156 * Execute a command or commands contained in a string.
12157 */
12158static int
12159evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012160{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012161 union node *n;
12162 struct stackmark smark;
12163 int skip;
12164
12165 setinputstring(s);
12166 setstackmark(&smark);
12167
12168 skip = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012169 while ((n = parsecmd(0)) != NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012170 evaltree(n, 0);
12171 popstackmark(&smark);
12172 skip = evalskip;
12173 if (skip)
12174 break;
12175 }
12176 popfile();
12177
12178 skip &= mask;
12179 evalskip = skip;
12180 return skip;
Eric Andersenc470f442003-07-28 09:56:35 +000012181}
12182
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012183/*
12184 * The eval command.
12185 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012186static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012187evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012188{
12189 char *p;
12190 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012191
Denis Vlasenko68404f12008-03-17 09:00:54 +000012192 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012193 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012194 argv += 2;
12195 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012196 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012197 for (;;) {
12198 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012199 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012200 if (p == NULL)
12201 break;
12202 STPUTC(' ', concat);
12203 }
12204 STPUTC('\0', concat);
12205 p = grabstackstr(concat);
12206 }
12207 evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012208 }
12209 return exitstatus;
12210}
12211
12212/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012213 * Read and execute commands.
12214 * "Top" is nonzero for the top level command loop;
12215 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012216 */
12217static int
12218cmdloop(int top)
12219{
12220 union node *n;
12221 struct stackmark smark;
12222 int inter;
12223 int numeof = 0;
12224
12225 TRACE(("cmdloop(%d) called\n", top));
12226 for (;;) {
12227 int skip;
12228
12229 setstackmark(&smark);
12230#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012231 if (doing_jobctl)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012232 showjobs(stderr, SHOW_CHANGED);
12233#endif
12234 inter = 0;
12235 if (iflag && top) {
12236 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012237 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012238 }
12239 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012240#if DEBUG
12241 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012242 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012243#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012244 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012245 if (!top || numeof >= 50)
12246 break;
12247 if (!stoppedjobs()) {
12248 if (!Iflag)
12249 break;
12250 out2str("\nUse \"exit\" to leave shell.\n");
12251 }
12252 numeof++;
12253 } else if (nflag == 0) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012254 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12255 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012256 numeof = 0;
12257 evaltree(n, 0);
12258 }
12259 popstackmark(&smark);
12260 skip = evalskip;
12261
12262 if (skip) {
12263 evalskip = 0;
12264 return skip & SKIPEVAL;
12265 }
12266 }
12267 return 0;
12268}
12269
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012270/*
12271 * Take commands from a file. To be compatible we should do a path
12272 * search for the file, which is necessary to find sub-commands.
12273 */
12274static char *
12275find_dot_file(char *name)
12276{
12277 char *fullname;
12278 const char *path = pathval();
12279 struct stat statb;
12280
12281 /* don't try this for absolute or relative paths */
12282 if (strchr(name, '/'))
12283 return name;
12284
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012285 /* IIRC standards do not say whether . is to be searched.
12286 * And it is even smaller this way, making it unconditional for now:
12287 */
12288 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12289 fullname = name;
12290 goto try_cur_dir;
12291 }
12292
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012293 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012294 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012295 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12296 /*
12297 * Don't bother freeing here, since it will
12298 * be freed by the caller.
12299 */
12300 return fullname;
12301 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012302 if (fullname != name)
12303 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012304 }
12305
12306 /* not found in the PATH */
12307 ash_msg_and_raise_error("%s: not found", name);
12308 /* NOTREACHED */
12309}
12310
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012311static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012312dotcmd(int argc, char **argv)
12313{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012314 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012315 struct strlist *sp;
12316 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012317
12318 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012319 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012320
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012321 if (!argv[1]) {
12322 /* bash says: "bash: .: filename argument required" */
12323 return 2; /* bash compat */
12324 }
12325
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012326 /* "false; . empty_file; echo $?" should print 0, not 1: */
12327 exitstatus = 0;
12328
Denys Vlasenko091f8312013-03-17 14:25:22 +010012329 /* This aborts if file isn't found, which is POSIXly correct.
12330 * bash returns exitcode 1 instead.
12331 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012332 fullname = find_dot_file(argv[1]);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012333 argv += 2;
12334 argc -= 2;
12335 if (argc) { /* argc > 0, argv[0] != NULL */
12336 saveparam = shellparam;
12337 shellparam.malloced = 0;
12338 shellparam.nparam = argc;
12339 shellparam.p = argv;
12340 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012341
Denys Vlasenko091f8312013-03-17 14:25:22 +010012342 /* This aborts if file can't be opened, which is POSIXly correct.
12343 * bash returns exitcode 1 instead.
12344 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012345 setinputfile(fullname, INPUT_PUSH_FILE);
12346 commandname = fullname;
12347 cmdloop(0);
12348 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012349
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012350 if (argc) {
12351 freeparam(&shellparam);
12352 shellparam = saveparam;
12353 };
12354
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012355 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012356}
12357
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012358static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012359exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012360{
12361 if (stoppedjobs())
12362 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012363 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012364 exitstatus = number(argv[1]);
12365 raise_exception(EXEXIT);
12366 /* NOTREACHED */
12367}
12368
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012369/*
12370 * Read a file containing shell functions.
12371 */
12372static void
12373readcmdfile(char *name)
12374{
12375 setinputfile(name, INPUT_PUSH_FILE);
12376 cmdloop(0);
12377 popfile();
12378}
12379
12380
Denis Vlasenkocc571512007-02-23 21:10:35 +000012381/* ============ find_command inplementation */
12382
12383/*
12384 * Resolve a command name. If you change this routine, you may have to
12385 * change the shellexec routine as well.
12386 */
12387static void
12388find_command(char *name, struct cmdentry *entry, int act, const char *path)
12389{
12390 struct tblentry *cmdp;
12391 int idx;
12392 int prev;
12393 char *fullname;
12394 struct stat statb;
12395 int e;
12396 int updatetbl;
12397 struct builtincmd *bcmd;
12398
12399 /* If name contains a slash, don't use PATH or hash table */
12400 if (strchr(name, '/') != NULL) {
12401 entry->u.index = -1;
12402 if (act & DO_ABS) {
12403 while (stat(name, &statb) < 0) {
12404#ifdef SYSV
12405 if (errno == EINTR)
12406 continue;
12407#endif
12408 entry->cmdtype = CMDUNKNOWN;
12409 return;
12410 }
12411 }
12412 entry->cmdtype = CMDNORMAL;
12413 return;
12414 }
12415
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012416/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012417
12418 updatetbl = (path == pathval());
12419 if (!updatetbl) {
12420 act |= DO_ALTPATH;
12421 if (strstr(path, "%builtin") != NULL)
12422 act |= DO_ALTBLTIN;
12423 }
12424
12425 /* If name is in the table, check answer will be ok */
12426 cmdp = cmdlookup(name, 0);
12427 if (cmdp != NULL) {
12428 int bit;
12429
12430 switch (cmdp->cmdtype) {
12431 default:
12432#if DEBUG
12433 abort();
12434#endif
12435 case CMDNORMAL:
12436 bit = DO_ALTPATH;
12437 break;
12438 case CMDFUNCTION:
12439 bit = DO_NOFUNC;
12440 break;
12441 case CMDBUILTIN:
12442 bit = DO_ALTBLTIN;
12443 break;
12444 }
12445 if (act & bit) {
12446 updatetbl = 0;
12447 cmdp = NULL;
12448 } else if (cmdp->rehash == 0)
12449 /* if not invalidated by cd, we're done */
12450 goto success;
12451 }
12452
12453 /* If %builtin not in path, check for builtin next */
12454 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012455 if (bcmd) {
12456 if (IS_BUILTIN_REGULAR(bcmd))
12457 goto builtin_success;
12458 if (act & DO_ALTPATH) {
12459 if (!(act & DO_ALTBLTIN))
12460 goto builtin_success;
12461 } else if (builtinloc <= 0) {
12462 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012463 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012464 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012465
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012466#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012467 {
12468 int applet_no = find_applet_by_name(name);
12469 if (applet_no >= 0) {
12470 entry->cmdtype = CMDNORMAL;
12471 entry->u.index = -2 - applet_no;
12472 return;
12473 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012474 }
12475#endif
12476
Denis Vlasenkocc571512007-02-23 21:10:35 +000012477 /* We have to search path. */
12478 prev = -1; /* where to start */
12479 if (cmdp && cmdp->rehash) { /* doing a rehash */
12480 if (cmdp->cmdtype == CMDBUILTIN)
12481 prev = builtinloc;
12482 else
12483 prev = cmdp->param.index;
12484 }
12485
12486 e = ENOENT;
12487 idx = -1;
12488 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012489 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012490 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012491 /* NB: code below will still use fullname
12492 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012493 idx++;
12494 if (pathopt) {
12495 if (prefix(pathopt, "builtin")) {
12496 if (bcmd)
12497 goto builtin_success;
12498 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012499 }
12500 if ((act & DO_NOFUNC)
12501 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012502 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012503 continue;
12504 }
12505 }
12506 /* if rehash, don't redo absolute path names */
12507 if (fullname[0] == '/' && idx <= prev) {
12508 if (idx < prev)
12509 continue;
12510 TRACE(("searchexec \"%s\": no change\n", name));
12511 goto success;
12512 }
12513 while (stat(fullname, &statb) < 0) {
12514#ifdef SYSV
12515 if (errno == EINTR)
12516 continue;
12517#endif
12518 if (errno != ENOENT && errno != ENOTDIR)
12519 e = errno;
12520 goto loop;
12521 }
12522 e = EACCES; /* if we fail, this will be the error */
12523 if (!S_ISREG(statb.st_mode))
12524 continue;
12525 if (pathopt) { /* this is a %func directory */
12526 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012527 /* NB: stalloc will return space pointed by fullname
12528 * (because we don't have any intervening allocations
12529 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012530 readcmdfile(fullname);
12531 cmdp = cmdlookup(name, 0);
12532 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12533 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12534 stunalloc(fullname);
12535 goto success;
12536 }
12537 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12538 if (!updatetbl) {
12539 entry->cmdtype = CMDNORMAL;
12540 entry->u.index = idx;
12541 return;
12542 }
12543 INT_OFF;
12544 cmdp = cmdlookup(name, 1);
12545 cmdp->cmdtype = CMDNORMAL;
12546 cmdp->param.index = idx;
12547 INT_ON;
12548 goto success;
12549 }
12550
12551 /* We failed. If there was an entry for this command, delete it */
12552 if (cmdp && updatetbl)
12553 delete_cmd_entry();
12554 if (act & DO_ERR)
12555 ash_msg("%s: %s", name, errmsg(e, "not found"));
12556 entry->cmdtype = CMDUNKNOWN;
12557 return;
12558
12559 builtin_success:
12560 if (!updatetbl) {
12561 entry->cmdtype = CMDBUILTIN;
12562 entry->u.cmd = bcmd;
12563 return;
12564 }
12565 INT_OFF;
12566 cmdp = cmdlookup(name, 1);
12567 cmdp->cmdtype = CMDBUILTIN;
12568 cmdp->param.cmd = bcmd;
12569 INT_ON;
12570 success:
12571 cmdp->rehash = 0;
12572 entry->cmdtype = cmdp->cmdtype;
12573 entry->u = cmdp->param;
12574}
12575
12576
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012577/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012578
Eric Andersencb57d552001-06-28 07:25:16 +000012579/*
Eric Andersencb57d552001-06-28 07:25:16 +000012580 * The trap builtin.
12581 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012582static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012583trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012584{
12585 char *action;
12586 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012587 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012588
Eric Andersenc470f442003-07-28 09:56:35 +000012589 nextopt(nullstr);
12590 ap = argptr;
12591 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012592 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012593 char *tr = trap_ptr[signo];
12594 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012595 /* note: bash adds "SIG", but only if invoked
12596 * as "bash". If called as "sh", or if set -o posix,
12597 * then it prints short signal names.
12598 * We are printing short names: */
12599 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012600 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012601 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012602 /* trap_ptr != trap only if we are in special-cased `trap` code.
12603 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012604 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012605 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012606 }
12607 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012608 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012609 if (trap_ptr != trap) {
12610 free(trap_ptr);
12611 trap_ptr = trap;
12612 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012613 */
Eric Andersencb57d552001-06-28 07:25:16 +000012614 return 0;
12615 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012616
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012617 action = NULL;
12618 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012619 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012620 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012621 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012622 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012623 if (signo < 0) {
12624 /* Mimic bash message exactly */
12625 ash_msg("%s: invalid signal specification", *ap);
12626 exitcode = 1;
12627 goto next;
12628 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012629 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012630 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012631 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012632 action = NULL;
12633 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012634 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012635 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012636 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012637 if (action)
12638 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012639 trap[signo] = action;
12640 if (signo != 0)
12641 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012642 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012643 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012644 ap++;
12645 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012646 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012647}
12648
Eric Andersenc470f442003-07-28 09:56:35 +000012649
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012650/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012651
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012652#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012653static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012654helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012655{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012656 unsigned col;
12657 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012658
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012659 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012660 "Built-in commands:\n"
12661 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012662 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012663 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012664 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012665 if (col > 60) {
12666 out1fmt("\n");
12667 col = 0;
12668 }
12669 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012670# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012671 {
12672 const char *a = applet_names;
12673 while (*a) {
12674 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12675 if (col > 60) {
12676 out1fmt("\n");
12677 col = 0;
12678 }
12679 a += strlen(a) + 1;
Eric Andersenc470f442003-07-28 09:56:35 +000012680 }
12681 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012682# endif
Eric Andersenc470f442003-07-28 09:56:35 +000012683 out1fmt("\n\n");
12684 return EXIT_SUCCESS;
12685}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012686#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012687
Flemming Madsend96ffda2013-04-07 18:47:24 +020012688#if MAX_HISTORY
12689static int FAST_FUNC
12690historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12691{
12692 show_history(line_input_state);
12693 return EXIT_SUCCESS;
12694}
12695#endif
12696
Eric Andersencb57d552001-06-28 07:25:16 +000012697/*
Eric Andersencb57d552001-06-28 07:25:16 +000012698 * The export and readonly commands.
12699 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012700static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012701exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012702{
12703 struct var *vp;
12704 char *name;
12705 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012706 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012707 char opt;
12708 int flag;
12709 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012710
Denys Vlasenkod5275882012-10-01 13:41:17 +020012711 /* "readonly" in bash accepts, but ignores -n.
12712 * We do the same: it saves a conditional in nextopt's param.
12713 */
12714 flag_off = 0;
12715 while ((opt = nextopt("np")) != '\0') {
12716 if (opt == 'n')
12717 flag_off = VEXPORT;
12718 }
12719 flag = VEXPORT;
12720 if (argv[0][0] == 'r') {
12721 flag = VREADONLY;
12722 flag_off = 0; /* readonly ignores -n */
12723 }
12724 flag_off = ~flag_off;
12725
12726 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12727 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012728 aptr = argptr;
12729 name = *aptr;
12730 if (name) {
12731 do {
12732 p = strchr(name, '=');
12733 if (p != NULL) {
12734 p++;
12735 } else {
12736 vp = *findvar(hashvar(name), name);
12737 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012738 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012739 continue;
12740 }
Eric Andersencb57d552001-06-28 07:25:16 +000012741 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012742 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012743 } while ((name = *++aptr) != NULL);
12744 return 0;
12745 }
Eric Andersencb57d552001-06-28 07:25:16 +000012746 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012747
12748 /* No arguments. Show the list of exported or readonly vars.
12749 * -n is ignored.
12750 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012751 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012752 return 0;
12753}
12754
Eric Andersencb57d552001-06-28 07:25:16 +000012755/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012756 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012757 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012758static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012759unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012760{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012761 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012762
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012763 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012764 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012765 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012766}
12767
Eric Andersencb57d552001-06-28 07:25:16 +000012768/*
Eric Andersencb57d552001-06-28 07:25:16 +000012769 * The unset builtin command. We unset the function before we unset the
12770 * variable to allow a function to be unset when there is a readonly variable
12771 * with the same name.
12772 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012773static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012774unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012775{
12776 char **ap;
12777 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012778 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012779 int ret = 0;
12780
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012781 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012782 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012783 }
Eric Andersencb57d552001-06-28 07:25:16 +000012784
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012785 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012786 if (flag != 'f') {
12787 i = unsetvar(*ap);
12788 ret |= i;
12789 if (!(i & 2))
12790 continue;
12791 }
12792 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012793 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012794 }
Eric Andersenc470f442003-07-28 09:56:35 +000012795 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012796}
12797
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012798static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012799 ' ', offsetof(struct tms, tms_utime),
12800 '\n', offsetof(struct tms, tms_stime),
12801 ' ', offsetof(struct tms, tms_cutime),
12802 '\n', offsetof(struct tms, tms_cstime),
12803 0
12804};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012805static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012806timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012807{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012808 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012809 const unsigned char *p;
12810 struct tms buf;
12811
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012812 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012813 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012814
12815 p = timescmd_str;
12816 do {
12817 t = *(clock_t *)(((char *) &buf) + p[1]);
12818 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012819 t = t % clk_tck;
12820 out1fmt("%lum%lu.%03lus%c",
12821 s / 60, s % 60,
12822 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012823 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012824 p += 2;
12825 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012826
Eric Andersencb57d552001-06-28 07:25:16 +000012827 return 0;
12828}
12829
Mike Frysinger98c52642009-04-02 10:02:37 +000012830#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012831/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012832 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012833 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012834 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012835 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012836 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012837static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012838letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012839{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012840 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012841
Denis Vlasenko68404f12008-03-17 09:00:54 +000012842 argv++;
12843 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012844 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012845 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012846 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012847 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012848
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012849 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012850}
Eric Andersenc470f442003-07-28 09:56:35 +000012851#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012852
Eric Andersenc470f442003-07-28 09:56:35 +000012853/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012854 * The read builtin. Options:
12855 * -r Do not interpret '\' specially
12856 * -s Turn off echo (tty only)
12857 * -n NCHARS Read NCHARS max
12858 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12859 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12860 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012861 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012862 * TODO: bash also has:
12863 * -a ARRAY Read into array[0],[1],etc
12864 * -d DELIM End on DELIM char, not newline
12865 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012866 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012867static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012868readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012869{
Denys Vlasenko73067272010-01-12 22:11:24 +010012870 char *opt_n = NULL;
12871 char *opt_p = NULL;
12872 char *opt_t = NULL;
12873 char *opt_u = NULL;
12874 int read_flags = 0;
12875 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012876 int i;
12877
Denys Vlasenko73067272010-01-12 22:11:24 +010012878 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012879 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012880 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012881 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012882 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012883 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012884 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012885 break;
12886 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012887 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012888 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012889 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012890 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012891 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012892 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012893 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012894 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012895 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012896 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012897 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012898 default:
12899 break;
12900 }
Eric Andersenc470f442003-07-28 09:56:35 +000012901 }
Paul Fox02eb9342005-09-07 16:56:02 +000012902
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012903 /* "read -s" needs to save/restore termios, can't allow ^C
12904 * to jump out of it.
12905 */
12906 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012907 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010012908 argptr,
12909 bltinlookup("IFS"), /* can be NULL */
12910 read_flags,
12911 opt_n,
12912 opt_p,
12913 opt_t,
12914 opt_u
12915 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012916 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012917
Denys Vlasenko73067272010-01-12 22:11:24 +010012918 if ((uintptr_t)r > 1)
12919 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012920
Denys Vlasenko73067272010-01-12 22:11:24 +010012921 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012922}
12923
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012924static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012925umaskcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012926{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012927 static const char permuser[3] ALIGN1 = "ugo";
12928 static const char permmode[3] ALIGN1 = "rwx";
12929 static const short permmask[] ALIGN2 = {
Eric Andersenc470f442003-07-28 09:56:35 +000012930 S_IRUSR, S_IWUSR, S_IXUSR,
12931 S_IRGRP, S_IWGRP, S_IXGRP,
12932 S_IROTH, S_IWOTH, S_IXOTH
12933 };
12934
Denis Vlasenkoeb858492009-04-18 02:06:54 +000012935 /* TODO: use bb_parse_mode() instead */
12936
Eric Andersenc470f442003-07-28 09:56:35 +000012937 char *ap;
12938 mode_t mask;
12939 int i;
12940 int symbolic_mode = 0;
12941
12942 while (nextopt("S") != '\0') {
12943 symbolic_mode = 1;
12944 }
12945
Denis Vlasenkob012b102007-02-19 22:43:01 +000012946 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012947 mask = umask(0);
12948 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012949 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000012950
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012951 ap = *argptr;
12952 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012953 if (symbolic_mode) {
12954 char buf[18];
12955 char *p = buf;
12956
12957 for (i = 0; i < 3; i++) {
12958 int j;
12959
12960 *p++ = permuser[i];
12961 *p++ = '=';
12962 for (j = 0; j < 3; j++) {
12963 if ((mask & permmask[3 * i + j]) == 0) {
12964 *p++ = permmode[j];
12965 }
12966 }
12967 *p++ = ',';
12968 }
12969 *--p = 0;
12970 puts(buf);
12971 } else {
12972 out1fmt("%.4o\n", mask);
12973 }
12974 } else {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012975 if (isdigit((unsigned char) *ap)) {
Eric Andersenc470f442003-07-28 09:56:35 +000012976 mask = 0;
12977 do {
12978 if (*ap >= '8' || *ap < '0')
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020012979 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012980 mask = (mask << 3) + (*ap - '0');
12981 } while (*++ap != '\0');
12982 umask(mask);
12983 } else {
12984 mask = ~mask & 0777;
12985 if (!bb_parse_mode(ap, &mask)) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000012986 ash_msg_and_raise_error("illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012987 }
12988 umask(~mask & 0777);
12989 }
12990 }
12991 return 0;
12992}
12993
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012994static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012995ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012996{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012997 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012998}
12999
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013000/* ============ main() and helpers */
13001
13002/*
13003 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013004 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013005static void
13006exitshell(void)
13007{
13008 struct jmploc loc;
13009 char *p;
13010 int status;
13011
Denys Vlasenkobede2152011-09-04 16:12:33 +020013012#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
13013 save_history(line_input_state);
13014#endif
13015
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013016 status = exitstatus;
13017 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
13018 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013019 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013020/* dash bug: it just does _exit(exitstatus) here
13021 * but we have to do setjobctl(0) first!
13022 * (bug is still not fixed in dash-0.5.3 - if you run dash
13023 * under Midnight Commander, on exit from dash MC is backgrounded) */
13024 status = exitstatus;
13025 goto out;
13026 }
13027 exception_handler = &loc;
13028 p = trap[0];
13029 if (p) {
13030 trap[0] = NULL;
13031 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020013032 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013033 }
13034 flush_stdout_stderr();
13035 out:
13036 setjobctl(0);
13037 _exit(status);
13038 /* NOTREACHED */
13039}
13040
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013041static void
13042init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013043{
13044 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013045 /* we will never free this */
13046 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013047
13048 /* from trap.c: */
13049 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013050 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13051 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13052 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013053 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013054
13055 /* from var.c: */
13056 {
13057 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013058 const char *p;
13059 struct stat st1, st2;
13060
13061 initvar();
13062 for (envp = environ; envp && *envp; envp++) {
13063 if (strchr(*envp, '=')) {
13064 setvareq(*envp, VEXPORT|VTEXTFIXED);
13065 }
13066 }
13067
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013068 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013069#if ENABLE_ASH_BASH_COMPAT
13070 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013071 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013072 if (!lookupvar("HOSTNAME")) {
13073 struct utsname uts;
13074 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013075 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013076 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013077#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013078 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013079 if (p) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013080 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013081 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13082 ) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013083 p = '\0';
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013084 }
13085 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013086 setpwd(p, 0);
13087 }
13088}
13089
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013090
13091//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013092//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013093//usage:#define ash_full_usage "\n\n"
13094//usage: "Unix shell interpreter"
13095
13096//usage:#if ENABLE_FEATURE_SH_IS_ASH
13097//usage:# define sh_trivial_usage ash_trivial_usage
13098//usage:# define sh_full_usage ash_full_usage
13099//usage:#endif
13100//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13101//usage:# define bash_trivial_usage ash_trivial_usage
13102//usage:# define bash_full_usage ash_full_usage
13103//usage:#endif
13104
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013105/*
13106 * Process the shell command line arguments.
13107 */
13108static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013109procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013110{
13111 int i;
13112 const char *xminusc;
13113 char **xargv;
13114
13115 xargv = argv;
13116 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013117 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013118 xargv++;
13119 for (i = 0; i < NOPTS; i++)
13120 optlist[i] = 2;
13121 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013122 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013123 /* it already printed err message */
13124 raise_exception(EXERROR);
13125 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013126 xargv = argptr;
13127 xminusc = minusc;
13128 if (*xargv == NULL) {
13129 if (xminusc)
13130 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13131 sflag = 1;
13132 }
13133 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13134 iflag = 1;
13135 if (mflag == 2)
13136 mflag = iflag;
13137 for (i = 0; i < NOPTS; i++)
13138 if (optlist[i] == 2)
13139 optlist[i] = 0;
13140#if DEBUG == 2
13141 debug = 1;
13142#endif
13143 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13144 if (xminusc) {
13145 minusc = *xargv++;
13146 if (*xargv)
13147 goto setarg0;
13148 } else if (!sflag) {
13149 setinputfile(*xargv, 0);
13150 setarg0:
13151 arg0 = *xargv++;
13152 commandname = arg0;
13153 }
13154
13155 shellparam.p = xargv;
13156#if ENABLE_ASH_GETOPTS
13157 shellparam.optind = 1;
13158 shellparam.optoff = -1;
13159#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013160 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013161 while (*xargv) {
13162 shellparam.nparam++;
13163 xargv++;
13164 }
13165 optschanged();
13166}
13167
13168/*
13169 * Read /etc/profile or .profile.
13170 */
13171static void
13172read_profile(const char *name)
13173{
13174 int skip;
13175
13176 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13177 return;
13178 skip = cmdloop(0);
13179 popfile();
13180 if (skip)
13181 exitshell();
13182}
13183
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013184/*
13185 * This routine is called when an error or an interrupt occurs in an
13186 * interactive shell and control is returned to the main command loop.
13187 */
13188static void
13189reset(void)
13190{
13191 /* from eval.c: */
13192 evalskip = 0;
13193 loopnest = 0;
13194 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013195 g_parsefile->left_in_buffer = 0;
13196 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013197 popallfiles();
13198 /* from parser.c: */
13199 tokpushback = 0;
13200 checkkwd = 0;
13201 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013202 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013203}
13204
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013205#if PROFILE
13206static short profile_buf[16384];
13207extern int etext();
13208#endif
13209
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013210/*
13211 * Main routine. We initialize things, parse the arguments, execute
13212 * profiles if we're a login shell, and then call cmdloop to execute
13213 * commands. The setjmp call sets up the location to jump to when an
13214 * exception occurs. When an exception occurs the variable "state"
13215 * is used to figure out how far we had gotten.
13216 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013217int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013218int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013219{
Mike Frysinger98c52642009-04-02 10:02:37 +000013220 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013221 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013222 struct jmploc jmploc;
13223 struct stackmark smark;
13224
Denis Vlasenko01631112007-12-16 17:20:38 +000013225 /* Initialize global data */
13226 INIT_G_misc();
13227 INIT_G_memstack();
13228 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013229#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013230 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013231#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013232 INIT_G_cmdtable();
13233
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013234#if PROFILE
13235 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13236#endif
13237
13238#if ENABLE_FEATURE_EDITING
13239 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13240#endif
13241 state = 0;
13242 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013243 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013244 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013245
13246 reset();
13247
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013248 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013249 if (e == EXERROR)
13250 exitstatus = 2;
13251 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013252 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013253 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013254 }
13255 if (e == EXINT) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013256 outcslow('\n', stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013257 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013258
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013259 popstackmark(&smark);
13260 FORCE_INT_ON; /* enable interrupts */
13261 if (s == 1)
13262 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013263 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013264 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013265 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013266 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013267 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013268 }
13269 exception_handler = &jmploc;
13270#if DEBUG
13271 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013272 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013273 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013274#endif
13275 rootpid = getpid();
13276
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013277 init();
13278 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013279 procargs(argv);
13280
Denys Vlasenko6088e132010-12-25 23:58:42 +010013281 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013282 isloginsh = 1;
13283 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013284 const char *hp;
13285
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013286 state = 1;
13287 read_profile("/etc/profile");
13288 state1:
13289 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013290 hp = lookupvar("HOME");
13291 if (hp) {
13292 hp = concat_path_file(hp, ".profile");
13293 read_profile(hp);
13294 free((char*)hp);
13295 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013296 }
13297 state2:
13298 state = 3;
13299 if (
13300#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013301 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013302#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013303 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013304 ) {
13305 shinit = lookupvar("ENV");
13306 if (shinit != NULL && *shinit != '\0') {
13307 read_profile(shinit);
13308 }
13309 }
13310 state3:
13311 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013312 if (minusc) {
13313 /* evalstring pushes parsefile stack.
13314 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013315 * is one of stacked source fds.
13316 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013317 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013318 // ^^ not necessary since now we special-case fd 0
13319 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013320 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013321 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013322
13323 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013324#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013325 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013326 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013327 if (!hp) {
13328 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013329 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013330 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013331 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013332 free((char*)hp);
13333 hp = lookupvar("HISTFILE");
13334 }
13335 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013336 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013337 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013338# if ENABLE_FEATURE_SH_HISTFILESIZE
13339 hp = lookupvar("HISTFILESIZE");
13340 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13341# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013342 }
13343#endif
13344 state4: /* XXX ??? - why isn't this before the "if" statement */
13345 cmdloop(1);
13346 }
13347#if PROFILE
13348 monitor(0);
13349#endif
13350#ifdef GPROF
13351 {
13352 extern void _mcleanup(void);
13353 _mcleanup();
13354 }
13355#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013356 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013357 exitshell();
13358 /* NOTREACHED */
13359}
13360
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013361
Eric Andersendf82f612001-06-28 07:46:40 +000013362/*-
13363 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013364 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013365 *
13366 * This code is derived from software contributed to Berkeley by
13367 * Kenneth Almquist.
13368 *
13369 * Redistribution and use in source and binary forms, with or without
13370 * modification, are permitted provided that the following conditions
13371 * are met:
13372 * 1. Redistributions of source code must retain the above copyright
13373 * notice, this list of conditions and the following disclaimer.
13374 * 2. Redistributions in binary form must reproduce the above copyright
13375 * notice, this list of conditions and the following disclaimer in the
13376 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013377 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013378 * may be used to endorse or promote products derived from this software
13379 * without specific prior written permission.
13380 *
13381 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13382 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13383 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13384 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13385 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13386 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13387 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13388 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13389 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13390 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13391 * SUCH DAMAGE.
13392 */