blob: 9a8bab5abaa0a8e9c34cfe094c6eef083f0d604c [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
Denys Vlasenko9c541002015-10-07 15:44:36 +0200540/* Was called outcslow(c,FILE*), but c was always '\n' */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000541static void
Denys Vlasenko9c541002015-10-07 15:44:36 +0200542newline_and_flush(FILE *dest)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000543{
544 INT_OFF;
Denys Vlasenko9c541002015-10-07 15:44:36 +0200545 putc('\n', dest);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000546 fflush(dest);
547 INT_ON;
548}
549
550static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
551static int
552out1fmt(const char *fmt, ...)
553{
554 va_list ap;
555 int r;
556
557 INT_OFF;
558 va_start(ap, fmt);
559 r = vprintf(fmt, ap);
560 va_end(ap);
561 INT_ON;
562 return r;
563}
564
565static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
566static int
567fmtstr(char *outbuf, size_t length, const char *fmt, ...)
568{
569 va_list ap;
570 int ret;
571
572 va_start(ap, fmt);
573 INT_OFF;
574 ret = vsnprintf(outbuf, length, fmt, ap);
575 va_end(ap);
576 INT_ON;
577 return ret;
578}
579
580static void
581out1str(const char *p)
582{
583 outstr(p, stdout);
584}
585
586static void
587out2str(const char *p)
588{
589 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100590 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000591}
592
593
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000594/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000595
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000596/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100597#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200598#define CTLESC ((unsigned char)'\201') /* escape next character */
599#define CTLVAR ((unsigned char)'\202') /* variable defn */
600#define CTLENDVAR ((unsigned char)'\203')
601#define CTLBACKQ ((unsigned char)'\204')
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200602#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
603#define CTLENDARI ((unsigned char)'\207')
604#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100605#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000606
607/* variable substitution byte (follows CTLVAR) */
608#define VSTYPE 0x0f /* type of variable substitution */
609#define VSNUL 0x10 /* colon--treat the empty string as unset */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000610
611/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000612#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
613#define VSMINUS 0x2 /* ${var-text} */
614#define VSPLUS 0x3 /* ${var+text} */
615#define VSQUESTION 0x4 /* ${var?message} */
616#define VSASSIGN 0x5 /* ${var=text} */
617#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
618#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
619#define VSTRIMLEFT 0x8 /* ${var#pattern} */
620#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
621#define VSLENGTH 0xa /* ${#var} */
622#if ENABLE_ASH_BASH_COMPAT
623#define VSSUBSTR 0xc /* ${var:position:length} */
624#define VSREPLACE 0xd /* ${var/pattern/replacement} */
625#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
626#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000627
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000628static const char dolatstr[] ALIGN1 = {
Ron Yorston549deab2015-05-18 09:57:51 +0200629 CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0'
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000630};
Ron Yorston549deab2015-05-18 09:57:51 +0200631#define DOLATSTRLEN 6
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000632
Denis Vlasenko559691a2008-10-05 18:39:31 +0000633#define NCMD 0
634#define NPIPE 1
635#define NREDIR 2
636#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000637#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000638#define NAND 5
639#define NOR 6
640#define NSEMI 7
641#define NIF 8
642#define NWHILE 9
643#define NUNTIL 10
644#define NFOR 11
645#define NCASE 12
646#define NCLIST 13
647#define NDEFUN 14
648#define NARG 15
649#define NTO 16
650#if ENABLE_ASH_BASH_COMPAT
651#define NTO2 17
652#endif
653#define NCLOBBER 18
654#define NFROM 19
655#define NFROMTO 20
656#define NAPPEND 21
657#define NTOFD 22
658#define NFROMFD 23
659#define NHERE 24
660#define NXHERE 25
661#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000662#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000663
664union node;
665
666struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000667 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000668 union node *assign;
669 union node *args;
670 union node *redirect;
671};
672
673struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000674 smallint type;
675 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000676 struct nodelist *cmdlist;
677};
678
679struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000680 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000681 union node *n;
682 union node *redirect;
683};
684
685struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000686 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000687 union node *ch1;
688 union node *ch2;
689};
690
691struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000692 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000693 union node *test;
694 union node *ifpart;
695 union node *elsepart;
696};
697
698struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000699 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000700 union node *args;
701 union node *body;
702 char *var;
703};
704
705struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000706 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000707 union node *expr;
708 union node *cases;
709};
710
711struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000712 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000713 union node *next;
714 union node *pattern;
715 union node *body;
716};
717
718struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000719 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000720 union node *next;
721 char *text;
722 struct nodelist *backquote;
723};
724
Denis Vlasenko559691a2008-10-05 18:39:31 +0000725/* nfile and ndup layout must match!
726 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
727 * that it is actually NTO2 (>&file), and change its type.
728 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000729struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000730 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000731 union node *next;
732 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000733 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000734 union node *fname;
735 char *expfname;
736};
737
738struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000739 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000740 union node *next;
741 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000742 int dupfd;
743 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000744 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000745};
746
747struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000748 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000749 union node *next;
750 int fd;
751 union node *doc;
752};
753
754struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000755 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000756 union node *com;
757};
758
759union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000760 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000761 struct ncmd ncmd;
762 struct npipe npipe;
763 struct nredir nredir;
764 struct nbinary nbinary;
765 struct nif nif;
766 struct nfor nfor;
767 struct ncase ncase;
768 struct nclist nclist;
769 struct narg narg;
770 struct nfile nfile;
771 struct ndup ndup;
772 struct nhere nhere;
773 struct nnot nnot;
774};
775
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200776/*
777 * NODE_EOF is returned by parsecmd when it encounters an end of file.
778 * It must be distinct from NULL.
779 */
780#define NODE_EOF ((union node *) -1L)
781
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000782struct nodelist {
783 struct nodelist *next;
784 union node *n;
785};
786
787struct funcnode {
788 int count;
789 union node n;
790};
791
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000792/*
793 * Free a parse tree.
794 */
795static void
796freefunc(struct funcnode *f)
797{
798 if (f && --f->count < 0)
799 free(f);
800}
801
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000802
803/* ============ Debugging output */
804
805#if DEBUG
806
807static FILE *tracefile;
808
809static void
810trace_printf(const char *fmt, ...)
811{
812 va_list va;
813
814 if (debug != 1)
815 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000816 if (DEBUG_TIME)
817 fprintf(tracefile, "%u ", (int) time(NULL));
818 if (DEBUG_PID)
819 fprintf(tracefile, "[%u] ", (int) getpid());
820 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200821 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000822 va_start(va, fmt);
823 vfprintf(tracefile, fmt, va);
824 va_end(va);
825}
826
827static void
828trace_vprintf(const char *fmt, va_list va)
829{
830 if (debug != 1)
831 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000832 if (DEBUG_TIME)
833 fprintf(tracefile, "%u ", (int) time(NULL));
834 if (DEBUG_PID)
835 fprintf(tracefile, "[%u] ", (int) getpid());
836 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200837 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000838 vfprintf(tracefile, fmt, va);
839}
840
841static void
842trace_puts(const char *s)
843{
844 if (debug != 1)
845 return;
846 fputs(s, tracefile);
847}
848
849static void
850trace_puts_quoted(char *s)
851{
852 char *p;
853 char c;
854
855 if (debug != 1)
856 return;
857 putc('"', tracefile);
858 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100859 switch ((unsigned char)*p) {
860 case '\n': c = 'n'; goto backslash;
861 case '\t': c = 't'; goto backslash;
862 case '\r': c = 'r'; goto backslash;
863 case '\"': c = '\"'; goto backslash;
864 case '\\': c = '\\'; goto backslash;
865 case CTLESC: c = 'e'; goto backslash;
866 case CTLVAR: c = 'v'; goto backslash;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100867 case CTLBACKQ: c = 'q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000868 backslash:
869 putc('\\', tracefile);
870 putc(c, tracefile);
871 break;
872 default:
873 if (*p >= ' ' && *p <= '~')
874 putc(*p, tracefile);
875 else {
876 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100877 putc((*p >> 6) & 03, tracefile);
878 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000879 putc(*p & 07, tracefile);
880 }
881 break;
882 }
883 }
884 putc('"', tracefile);
885}
886
887static void
888trace_puts_args(char **ap)
889{
890 if (debug != 1)
891 return;
892 if (!*ap)
893 return;
894 while (1) {
895 trace_puts_quoted(*ap);
896 if (!*++ap) {
897 putc('\n', tracefile);
898 break;
899 }
900 putc(' ', tracefile);
901 }
902}
903
904static void
905opentrace(void)
906{
907 char s[100];
908#ifdef O_APPEND
909 int flags;
910#endif
911
912 if (debug != 1) {
913 if (tracefile)
914 fflush(tracefile);
915 /* leave open because libedit might be using it */
916 return;
917 }
918 strcpy(s, "./trace");
919 if (tracefile) {
920 if (!freopen(s, "a", tracefile)) {
921 fprintf(stderr, "Can't re-open %s\n", s);
922 debug = 0;
923 return;
924 }
925 } else {
926 tracefile = fopen(s, "a");
927 if (tracefile == NULL) {
928 fprintf(stderr, "Can't open %s\n", s);
929 debug = 0;
930 return;
931 }
932 }
933#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000934 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000935 if (flags >= 0)
936 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
937#endif
938 setlinebuf(tracefile);
939 fputs("\nTracing started.\n", tracefile);
940}
941
942static void
943indent(int amount, char *pfx, FILE *fp)
944{
945 int i;
946
947 for (i = 0; i < amount; i++) {
948 if (pfx && i == amount - 1)
949 fputs(pfx, fp);
950 putc('\t', fp);
951 }
952}
953
954/* little circular references here... */
955static void shtree(union node *n, int ind, char *pfx, FILE *fp);
956
957static void
958sharg(union node *arg, FILE *fp)
959{
960 char *p;
961 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100962 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000963
964 if (arg->type != NARG) {
965 out1fmt("<node type %d>\n", arg->type);
966 abort();
967 }
968 bqlist = arg->narg.backquote;
969 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100970 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000971 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700972 p++;
973 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000974 break;
975 case CTLVAR:
976 putc('$', fp);
977 putc('{', fp);
978 subtype = *++p;
979 if (subtype == VSLENGTH)
980 putc('#', fp);
981
Dan Fandrich77d48722010-09-07 23:38:28 -0700982 while (*p != '=') {
983 putc(*p, fp);
984 p++;
985 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000986
987 if (subtype & VSNUL)
988 putc(':', fp);
989
990 switch (subtype & VSTYPE) {
991 case VSNORMAL:
992 putc('}', fp);
993 break;
994 case VSMINUS:
995 putc('-', fp);
996 break;
997 case VSPLUS:
998 putc('+', fp);
999 break;
1000 case VSQUESTION:
1001 putc('?', fp);
1002 break;
1003 case VSASSIGN:
1004 putc('=', fp);
1005 break;
1006 case VSTRIMLEFT:
1007 putc('#', fp);
1008 break;
1009 case VSTRIMLEFTMAX:
1010 putc('#', fp);
1011 putc('#', fp);
1012 break;
1013 case VSTRIMRIGHT:
1014 putc('%', fp);
1015 break;
1016 case VSTRIMRIGHTMAX:
1017 putc('%', fp);
1018 putc('%', fp);
1019 break;
1020 case VSLENGTH:
1021 break;
1022 default:
1023 out1fmt("<subtype %d>", subtype);
1024 }
1025 break;
1026 case CTLENDVAR:
1027 putc('}', fp);
1028 break;
1029 case CTLBACKQ:
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001030 putc('$', fp);
1031 putc('(', fp);
1032 shtree(bqlist->n, -1, NULL, fp);
1033 putc(')', fp);
1034 break;
1035 default:
1036 putc(*p, fp);
1037 break;
1038 }
1039 }
1040}
1041
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001042static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001043shcmd(union node *cmd, FILE *fp)
1044{
1045 union node *np;
1046 int first;
1047 const char *s;
1048 int dftfd;
1049
1050 first = 1;
1051 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001052 if (!first)
1053 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001054 sharg(np, fp);
1055 first = 0;
1056 }
1057 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001058 if (!first)
1059 putc(' ', fp);
1060 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001061 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001062 case NTO: s = ">>"+1; dftfd = 1; break;
1063 case NCLOBBER: s = ">|"; dftfd = 1; break;
1064 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001065#if ENABLE_ASH_BASH_COMPAT
1066 case NTO2:
1067#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001068 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001069 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001070 case NFROMFD: s = "<&"; break;
1071 case NFROMTO: s = "<>"; break;
1072 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001073 }
1074 if (np->nfile.fd != dftfd)
1075 fprintf(fp, "%d", np->nfile.fd);
1076 fputs(s, fp);
1077 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1078 fprintf(fp, "%d", np->ndup.dupfd);
1079 } else {
1080 sharg(np->nfile.fname, fp);
1081 }
1082 first = 0;
1083 }
1084}
1085
1086static void
1087shtree(union node *n, int ind, char *pfx, FILE *fp)
1088{
1089 struct nodelist *lp;
1090 const char *s;
1091
1092 if (n == NULL)
1093 return;
1094
1095 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001096
1097 if (n == NODE_EOF) {
1098 fputs("<EOF>", fp);
1099 return;
1100 }
1101
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001102 switch (n->type) {
1103 case NSEMI:
1104 s = "; ";
1105 goto binop;
1106 case NAND:
1107 s = " && ";
1108 goto binop;
1109 case NOR:
1110 s = " || ";
1111 binop:
1112 shtree(n->nbinary.ch1, ind, NULL, fp);
1113 /* if (ind < 0) */
1114 fputs(s, fp);
1115 shtree(n->nbinary.ch2, ind, NULL, fp);
1116 break;
1117 case NCMD:
1118 shcmd(n, fp);
1119 if (ind >= 0)
1120 putc('\n', fp);
1121 break;
1122 case NPIPE:
1123 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001124 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001125 if (lp->next)
1126 fputs(" | ", fp);
1127 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001128 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001129 fputs(" &", fp);
1130 if (ind >= 0)
1131 putc('\n', fp);
1132 break;
1133 default:
1134 fprintf(fp, "<node type %d>", n->type);
1135 if (ind >= 0)
1136 putc('\n', fp);
1137 break;
1138 }
1139}
1140
1141static void
1142showtree(union node *n)
1143{
1144 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001145 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001146}
1147
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001148#endif /* DEBUG */
1149
1150
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001151/* ============ Parser data */
1152
1153/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001154 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1155 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001156struct strlist {
1157 struct strlist *next;
1158 char *text;
1159};
1160
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001161struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001162
Denis Vlasenkob012b102007-02-19 22:43:01 +00001163struct strpush {
1164 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001165 char *prev_string;
1166 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001167#if ENABLE_ASH_ALIAS
1168 struct alias *ap; /* if push was associated with an alias */
1169#endif
1170 char *string; /* remember the string since it may change */
1171};
1172
1173struct parsefile {
1174 struct parsefile *prev; /* preceding file on stack */
1175 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001176 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001177 int left_in_line; /* number of chars left in this line */
1178 int left_in_buffer; /* number of chars left in this buffer past the line */
1179 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001180 char *buf; /* input buffer */
1181 struct strpush *strpush; /* for pushing strings at this level */
1182 struct strpush basestrpush; /* so pushing one is fast */
1183};
1184
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001185static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001186static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001187static int startlinno; /* line # where last token started */
1188static char *commandname; /* currently executing command */
1189static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001190static uint8_t exitstatus; /* exit status of last command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001191
1192
1193/* ============ Message printing */
1194
1195static void
1196ash_vmsg(const char *msg, va_list ap)
1197{
1198 fprintf(stderr, "%s: ", arg0);
1199 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001200 if (strcmp(arg0, commandname))
1201 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001202 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001203 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001204 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001205 vfprintf(stderr, msg, ap);
Denys Vlasenko9c541002015-10-07 15:44:36 +02001206 newline_and_flush(stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001207}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001208
1209/*
1210 * Exverror is called to raise the error exception. If the second argument
1211 * is not NULL then error prints an error message using printf style
1212 * formatting. It then raises the error exception.
1213 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001214static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001215static void
1216ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001217{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001218#if DEBUG
1219 if (msg) {
1220 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1221 TRACEV((msg, ap));
1222 TRACE(("\") pid=%d\n", getpid()));
1223 } else
1224 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1225 if (msg)
1226#endif
1227 ash_vmsg(msg, ap);
1228
1229 flush_stdout_stderr();
1230 raise_exception(cond);
1231 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001232}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001233
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001234static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001235static void
1236ash_msg_and_raise_error(const char *msg, ...)
1237{
1238 va_list ap;
1239
1240 va_start(ap, msg);
1241 ash_vmsg_and_raise(EXERROR, msg, ap);
1242 /* NOTREACHED */
1243 va_end(ap);
1244}
1245
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001246static void raise_error_syntax(const char *) NORETURN;
1247static void
1248raise_error_syntax(const char *msg)
1249{
1250 ash_msg_and_raise_error("syntax error: %s", msg);
1251 /* NOTREACHED */
1252}
1253
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001254static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001255static void
1256ash_msg_and_raise(int cond, const char *msg, ...)
1257{
1258 va_list ap;
1259
1260 va_start(ap, msg);
1261 ash_vmsg_and_raise(cond, msg, ap);
1262 /* NOTREACHED */
1263 va_end(ap);
1264}
1265
1266/*
1267 * error/warning routines for external builtins
1268 */
1269static void
1270ash_msg(const char *fmt, ...)
1271{
1272 va_list ap;
1273
1274 va_start(ap, fmt);
1275 ash_vmsg(fmt, ap);
1276 va_end(ap);
1277}
1278
1279/*
1280 * Return a string describing an error. The returned string may be a
1281 * pointer to a static buffer that will be overwritten on the next call.
1282 * Action describes the operation that got the error.
1283 */
1284static const char *
1285errmsg(int e, const char *em)
1286{
1287 if (e == ENOENT || e == ENOTDIR) {
1288 return em;
1289 }
1290 return strerror(e);
1291}
1292
1293
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001294/* ============ Memory allocation */
1295
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001296#if 0
1297/* I consider these wrappers nearly useless:
1298 * ok, they return you to nearest exception handler, but
1299 * how much memory do you leak in the process, making
1300 * memory starvation worse?
1301 */
1302static void *
1303ckrealloc(void * p, size_t nbytes)
1304{
1305 p = realloc(p, nbytes);
1306 if (!p)
1307 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1308 return p;
1309}
1310
1311static void *
1312ckmalloc(size_t nbytes)
1313{
1314 return ckrealloc(NULL, nbytes);
1315}
1316
1317static void *
1318ckzalloc(size_t nbytes)
1319{
1320 return memset(ckmalloc(nbytes), 0, nbytes);
1321}
1322
1323static char *
1324ckstrdup(const char *s)
1325{
1326 char *p = strdup(s);
1327 if (!p)
1328 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1329 return p;
1330}
1331#else
1332/* Using bbox equivalents. They exit if out of memory */
1333# define ckrealloc xrealloc
1334# define ckmalloc xmalloc
1335# define ckzalloc xzalloc
1336# define ckstrdup xstrdup
1337#endif
1338
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001339/*
1340 * It appears that grabstackstr() will barf with such alignments
1341 * because stalloc() will return a string allocated in a new stackblock.
1342 */
1343#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1344enum {
1345 /* Most machines require the value returned from malloc to be aligned
1346 * in some way. The following macro will get this right
1347 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001348 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001349 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001350 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001351};
1352
1353struct stack_block {
1354 struct stack_block *prev;
1355 char space[MINSIZE];
1356};
1357
1358struct stackmark {
1359 struct stack_block *stackp;
1360 char *stacknxt;
1361 size_t stacknleft;
1362 struct stackmark *marknext;
1363};
1364
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001365
Denis Vlasenko01631112007-12-16 17:20:38 +00001366struct globals_memstack {
1367 struct stack_block *g_stackp; // = &stackbase;
1368 struct stackmark *markp;
1369 char *g_stacknxt; // = stackbase.space;
1370 char *sstrend; // = stackbase.space + MINSIZE;
1371 size_t g_stacknleft; // = MINSIZE;
1372 int herefd; // = -1;
1373 struct stack_block stackbase;
1374};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001375extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1376#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001377#define g_stackp (G_memstack.g_stackp )
1378#define markp (G_memstack.markp )
1379#define g_stacknxt (G_memstack.g_stacknxt )
1380#define sstrend (G_memstack.sstrend )
1381#define g_stacknleft (G_memstack.g_stacknleft)
1382#define herefd (G_memstack.herefd )
1383#define stackbase (G_memstack.stackbase )
1384#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001385 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1386 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001387 g_stackp = &stackbase; \
1388 g_stacknxt = stackbase.space; \
1389 g_stacknleft = MINSIZE; \
1390 sstrend = stackbase.space + MINSIZE; \
1391 herefd = -1; \
1392} while (0)
1393
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001394
Denis Vlasenko01631112007-12-16 17:20:38 +00001395#define stackblock() ((void *)g_stacknxt)
1396#define stackblocksize() g_stacknleft
1397
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001398/*
1399 * Parse trees for commands are allocated in lifo order, so we use a stack
1400 * to make this more efficient, and also to avoid all sorts of exception
1401 * handling code to handle interrupts in the middle of a parse.
1402 *
1403 * The size 504 was chosen because the Ultrix malloc handles that size
1404 * well.
1405 */
1406static void *
1407stalloc(size_t nbytes)
1408{
1409 char *p;
1410 size_t aligned;
1411
1412 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001413 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001414 size_t len;
1415 size_t blocksize;
1416 struct stack_block *sp;
1417
1418 blocksize = aligned;
1419 if (blocksize < MINSIZE)
1420 blocksize = MINSIZE;
1421 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1422 if (len < blocksize)
1423 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1424 INT_OFF;
1425 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001426 sp->prev = g_stackp;
1427 g_stacknxt = sp->space;
1428 g_stacknleft = blocksize;
1429 sstrend = g_stacknxt + blocksize;
1430 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001431 INT_ON;
1432 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001433 p = g_stacknxt;
1434 g_stacknxt += aligned;
1435 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001436 return p;
1437}
1438
Denis Vlasenko597906c2008-02-20 16:38:54 +00001439static void *
1440stzalloc(size_t nbytes)
1441{
1442 return memset(stalloc(nbytes), 0, nbytes);
1443}
1444
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001445static void
1446stunalloc(void *p)
1447{
1448#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001449 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001450 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001451 abort();
1452 }
1453#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001454 g_stacknleft += g_stacknxt - (char *)p;
1455 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001456}
1457
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001458/*
1459 * Like strdup but works with the ash stack.
1460 */
1461static char *
1462ststrdup(const char *p)
1463{
1464 size_t len = strlen(p) + 1;
1465 return memcpy(stalloc(len), p, len);
1466}
1467
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001468static void
1469setstackmark(struct stackmark *mark)
1470{
Denis Vlasenko01631112007-12-16 17:20:38 +00001471 mark->stackp = g_stackp;
1472 mark->stacknxt = g_stacknxt;
1473 mark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001474 mark->marknext = markp;
1475 markp = mark;
1476}
1477
1478static void
1479popstackmark(struct stackmark *mark)
1480{
1481 struct stack_block *sp;
1482
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001483 if (!mark->stackp)
1484 return;
1485
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001486 INT_OFF;
1487 markp = mark->marknext;
Denis Vlasenko01631112007-12-16 17:20:38 +00001488 while (g_stackp != mark->stackp) {
1489 sp = g_stackp;
1490 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001491 free(sp);
1492 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001493 g_stacknxt = mark->stacknxt;
1494 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001495 sstrend = mark->stacknxt + mark->stacknleft;
1496 INT_ON;
1497}
1498
1499/*
1500 * When the parser reads in a string, it wants to stick the string on the
1501 * stack and only adjust the stack pointer when it knows how big the
1502 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1503 * of space on top of the stack and stackblocklen returns the length of
1504 * this block. Growstackblock will grow this space by at least one byte,
1505 * possibly moving it (like realloc). Grabstackblock actually allocates the
1506 * part of the block that has been used.
1507 */
1508static void
1509growstackblock(void)
1510{
1511 size_t newlen;
1512
Denis Vlasenko01631112007-12-16 17:20:38 +00001513 newlen = g_stacknleft * 2;
1514 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001515 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1516 if (newlen < 128)
1517 newlen += 128;
1518
Denis Vlasenko01631112007-12-16 17:20:38 +00001519 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001520 struct stack_block *oldstackp;
1521 struct stackmark *xmark;
1522 struct stack_block *sp;
1523 struct stack_block *prevstackp;
1524 size_t grosslen;
1525
1526 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001527 oldstackp = g_stackp;
1528 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001529 prevstackp = sp->prev;
1530 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1531 sp = ckrealloc(sp, grosslen);
1532 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001533 g_stackp = sp;
1534 g_stacknxt = sp->space;
1535 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001536 sstrend = sp->space + newlen;
1537
1538 /*
1539 * Stack marks pointing to the start of the old block
1540 * must be relocated to point to the new block
1541 */
1542 xmark = markp;
1543 while (xmark != NULL && xmark->stackp == oldstackp) {
Denis Vlasenko01631112007-12-16 17:20:38 +00001544 xmark->stackp = g_stackp;
1545 xmark->stacknxt = g_stacknxt;
1546 xmark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001547 xmark = xmark->marknext;
1548 }
1549 INT_ON;
1550 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001551 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001552 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001553 char *p = stalloc(newlen);
1554
1555 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001556 g_stacknxt = memcpy(p, oldspace, oldlen);
1557 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001558 }
1559}
1560
1561static void
1562grabstackblock(size_t len)
1563{
1564 len = SHELL_ALIGN(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001565 g_stacknxt += len;
1566 g_stacknleft -= len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001567}
1568
1569/*
1570 * The following routines are somewhat easier to use than the above.
1571 * The user declares a variable of type STACKSTR, which may be declared
1572 * to be a register. The macro STARTSTACKSTR initializes things. Then
1573 * the user uses the macro STPUTC to add characters to the string. In
1574 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1575 * grown as necessary. When the user is done, she can just leave the
1576 * string there and refer to it using stackblock(). Or she can allocate
1577 * the space for it using grabstackstr(). If it is necessary to allow
1578 * someone else to use the stack temporarily and then continue to grow
1579 * the string, the user should use grabstack to allocate the space, and
1580 * then call ungrabstr(p) to return to the previous mode of operation.
1581 *
1582 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1583 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1584 * is space for at least one character.
1585 */
1586static void *
1587growstackstr(void)
1588{
1589 size_t len = stackblocksize();
1590 if (herefd >= 0 && len >= 1024) {
1591 full_write(herefd, stackblock(), len);
1592 return stackblock();
1593 }
1594 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001595 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001596}
1597
1598/*
1599 * Called from CHECKSTRSPACE.
1600 */
1601static char *
1602makestrspace(size_t newlen, char *p)
1603{
Denis Vlasenko01631112007-12-16 17:20:38 +00001604 size_t len = p - g_stacknxt;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001605 size_t size = stackblocksize();
1606
1607 for (;;) {
1608 size_t nleft;
1609
1610 size = stackblocksize();
1611 nleft = size - len;
1612 if (nleft >= newlen)
1613 break;
1614 growstackblock();
1615 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001616 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001617}
1618
1619static char *
1620stack_nputstr(const char *s, size_t n, char *p)
1621{
1622 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001623 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001624 return p;
1625}
1626
1627static char *
1628stack_putstr(const char *s, char *p)
1629{
1630 return stack_nputstr(s, strlen(s), p);
1631}
1632
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001633static char *
1634_STPUTC(int c, char *p)
1635{
1636 if (p == sstrend)
1637 p = growstackstr();
1638 *p++ = c;
1639 return p;
1640}
1641
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001642#define STARTSTACKSTR(p) ((p) = stackblock())
1643#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001644#define CHECKSTRSPACE(n, p) do { \
1645 char *q = (p); \
1646 size_t l = (n); \
1647 size_t m = sstrend - q; \
1648 if (l > m) \
1649 (p) = makestrspace(l, q); \
1650} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001651#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001652#define STACKSTRNUL(p) do { \
1653 if ((p) == sstrend) \
1654 (p) = growstackstr(); \
1655 *(p) = '\0'; \
1656} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001657#define STUNPUTC(p) (--(p))
1658#define STTOPC(p) ((p)[-1])
1659#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001660
1661#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001662#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001663#define stackstrend() ((void *)sstrend)
1664
1665
1666/* ============ String helpers */
1667
1668/*
1669 * prefix -- see if pfx is a prefix of string.
1670 */
1671static char *
1672prefix(const char *string, const char *pfx)
1673{
1674 while (*pfx) {
1675 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001676 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001677 }
1678 return (char *) string;
1679}
1680
1681/*
1682 * Check for a valid number. This should be elsewhere.
1683 */
1684static int
1685is_number(const char *p)
1686{
1687 do {
1688 if (!isdigit(*p))
1689 return 0;
1690 } while (*++p != '\0');
1691 return 1;
1692}
1693
1694/*
1695 * Convert a string of digits to an integer, printing an error message on
1696 * failure.
1697 */
1698static int
1699number(const char *s)
1700{
1701 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001702 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001703 return atoi(s);
1704}
1705
1706/*
1707 * Produce a possibly single quoted string suitable as input to the shell.
1708 * The return string is allocated on the stack.
1709 */
1710static char *
1711single_quote(const char *s)
1712{
1713 char *p;
1714
1715 STARTSTACKSTR(p);
1716
1717 do {
1718 char *q;
1719 size_t len;
1720
1721 len = strchrnul(s, '\'') - s;
1722
1723 q = p = makestrspace(len + 3, p);
1724
1725 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001726 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001727 *q++ = '\'';
1728 s += len;
1729
1730 STADJUST(q - p, p);
1731
Denys Vlasenkocd716832009-11-28 22:14:02 +01001732 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001733 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001734 len = 0;
1735 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001736
1737 q = p = makestrspace(len + 3, p);
1738
1739 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001740 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001741 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001742
1743 STADJUST(q - p, p);
1744 } while (*s);
1745
Denys Vlasenkocd716832009-11-28 22:14:02 +01001746 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001747
1748 return stackblock();
1749}
1750
1751
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001752/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001753
1754static char **argptr; /* argument list for builtin commands */
1755static char *optionarg; /* set by nextopt (like getopt) */
1756static char *optptr; /* used by nextopt */
1757
1758/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001759 * XXX - should get rid of. Have all builtins use getopt(3).
1760 * The library getopt must have the BSD extension static variable
1761 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001762 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001763 * Standard option processing (a la getopt) for builtin routines.
1764 * The only argument that is passed to nextopt is the option string;
1765 * the other arguments are unnecessary. It returns the character,
1766 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001767 */
1768static int
1769nextopt(const char *optstring)
1770{
1771 char *p;
1772 const char *q;
1773 char c;
1774
1775 p = optptr;
1776 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001777 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001778 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001779 if (p == NULL)
1780 return '\0';
1781 if (*p != '-')
1782 return '\0';
1783 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001784 return '\0';
1785 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001786 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001787 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001788 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001789 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001790 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001792 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001793 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001794 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001795 if (*++q == ':')
1796 q++;
1797 }
1798 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001799 if (*p == '\0') {
1800 p = *argptr++;
1801 if (p == NULL)
1802 ash_msg_and_raise_error("no arg for -%c option", c);
1803 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001804 optionarg = p;
1805 p = NULL;
1806 }
1807 optptr = p;
1808 return c;
1809}
1810
1811
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001812/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001813
Denis Vlasenko01631112007-12-16 17:20:38 +00001814/*
1815 * The parsefile structure pointed to by the global variable parsefile
1816 * contains information about the current file being read.
1817 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001818struct shparam {
1819 int nparam; /* # of positional parameters (without $0) */
1820#if ENABLE_ASH_GETOPTS
1821 int optind; /* next parameter to be processed by getopts */
1822 int optoff; /* used by getopts */
1823#endif
1824 unsigned char malloced; /* if parameter list dynamically allocated */
1825 char **p; /* parameter list */
1826};
1827
1828/*
1829 * Free the list of positional parameters.
1830 */
1831static void
1832freeparam(volatile struct shparam *param)
1833{
Denis Vlasenko01631112007-12-16 17:20:38 +00001834 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001835 char **ap, **ap1;
1836 ap = ap1 = param->p;
1837 while (*ap)
1838 free(*ap++);
1839 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001840 }
1841}
1842
1843#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001844static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001845#endif
1846
1847struct var {
1848 struct var *next; /* next entry in hash list */
1849 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001850 const char *var_text; /* name=value */
1851 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001852 /* the variable gets set/unset */
1853};
1854
1855struct localvar {
1856 struct localvar *next; /* next local variable in list */
1857 struct var *vp; /* the variable that was made local */
1858 int flags; /* saved flags */
1859 const char *text; /* saved text */
1860};
1861
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001862/* flags */
1863#define VEXPORT 0x01 /* variable is exported */
1864#define VREADONLY 0x02 /* variable cannot be modified */
1865#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1866#define VTEXTFIXED 0x08 /* text is statically allocated */
1867#define VSTACK 0x10 /* text is allocated on the stack */
1868#define VUNSET 0x20 /* the variable is not set */
1869#define VNOFUNC 0x40 /* don't call the callback function */
1870#define VNOSET 0x80 /* do not set variable - just readonly test */
1871#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001872#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001873# define VDYNAMIC 0x200 /* dynamic variable */
1874#else
1875# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001876#endif
1877
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001878
Denis Vlasenko01631112007-12-16 17:20:38 +00001879/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001880#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001881static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001882change_lc_all(const char *value)
1883{
1884 if (value && *value != '\0')
1885 setlocale(LC_ALL, value);
1886}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001887static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001888change_lc_ctype(const char *value)
1889{
1890 if (value && *value != '\0')
1891 setlocale(LC_CTYPE, value);
1892}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001893#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001894#if ENABLE_ASH_MAIL
1895static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001896static void changemail(const char *var_value) FAST_FUNC;
1897#else
1898# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001899#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001900static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001901#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001902static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001903#endif
1904
Denis Vlasenko01631112007-12-16 17:20:38 +00001905static const struct {
1906 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001907 const char *var_text;
1908 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001909} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001910 /*
1911 * Note: VEXPORT would not work correctly here for NOFORK applets:
1912 * some environment strings may be constant.
1913 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001914 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001915#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001916 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1917 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001918#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001919 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1920 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1921 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1922 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001923#if ENABLE_ASH_GETOPTS
Denis Vlasenko01631112007-12-16 17:20:38 +00001924 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001925#endif
1926#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001927 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001928#endif
1929#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001930 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1931 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001932#endif
1933#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001934 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001935#endif
1936};
1937
Denis Vlasenko0b769642008-07-24 07:54:57 +00001938struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001939
1940struct globals_var {
1941 struct shparam shellparam; /* $@ current positional parameters */
1942 struct redirtab *redirlist;
1943 int g_nullredirs;
1944 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1945 struct var *vartab[VTABSIZE];
1946 struct var varinit[ARRAY_SIZE(varinit_data)];
1947};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001948extern struct globals_var *const ash_ptr_to_globals_var;
1949#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001950#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001951//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001952#define g_nullredirs (G_var.g_nullredirs )
1953#define preverrout_fd (G_var.preverrout_fd)
1954#define vartab (G_var.vartab )
1955#define varinit (G_var.varinit )
1956#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001957 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001958 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1959 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001960 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001961 varinit[i].flags = varinit_data[i].flags; \
1962 varinit[i].var_text = varinit_data[i].var_text; \
1963 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001964 } \
1965} while (0)
1966
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001967#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001968#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001969# define vmail (&vifs)[1]
1970# define vmpath (&vmail)[1]
1971# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001972#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001973# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001974#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001975#define vps1 (&vpath)[1]
1976#define vps2 (&vps1)[1]
1977#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001978#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001979# define voptind (&vps4)[1]
1980# if ENABLE_ASH_RANDOM_SUPPORT
1981# define vrandom (&voptind)[1]
1982# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001983#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001984# if ENABLE_ASH_RANDOM_SUPPORT
1985# define vrandom (&vps4)[1]
1986# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001987#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001988
1989/*
1990 * The following macros access the values of the above variables.
1991 * They have to skip over the name. They return the null string
1992 * for unset variables.
1993 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001994#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001995#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001996#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001997# define mailval() (vmail.var_text + 5)
1998# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001999# define mpathset() ((vmpath.flags & VUNSET) == 0)
2000#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002001#define pathval() (vpath.var_text + 5)
2002#define ps1val() (vps1.var_text + 4)
2003#define ps2val() (vps2.var_text + 4)
2004#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002005#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002006# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002007#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002008
Denis Vlasenko01631112007-12-16 17:20:38 +00002009#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002010static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002011getoptsreset(const char *value)
2012{
2013 shellparam.optind = number(value);
2014 shellparam.optoff = -1;
2015}
2016#endif
2017
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002018/*
2019 * Compares two strings up to the first = or '\0'. The first
2020 * string must be terminated by '='; the second may be terminated by
2021 * either '=' or '\0'.
2022 */
2023static int
2024varcmp(const char *p, const char *q)
2025{
2026 int c, d;
2027
2028 while ((c = *p) == (d = *q)) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002029 if (c == '\0' || c == '=')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002030 goto out;
2031 p++;
2032 q++;
2033 }
2034 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002035 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002036 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002037 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002038 out:
2039 return c - d;
2040}
2041
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002042/*
2043 * Find the appropriate entry in the hash table from the name.
2044 */
2045static struct var **
2046hashvar(const char *p)
2047{
2048 unsigned hashval;
2049
2050 hashval = ((unsigned char) *p) << 4;
2051 while (*p && *p != '=')
2052 hashval += (unsigned char) *p++;
2053 return &vartab[hashval % VTABSIZE];
2054}
2055
2056static int
2057vpcmp(const void *a, const void *b)
2058{
2059 return varcmp(*(const char **)a, *(const char **)b);
2060}
2061
2062/*
2063 * This routine initializes the builtin variables.
2064 */
2065static void
2066initvar(void)
2067{
2068 struct var *vp;
2069 struct var *end;
2070 struct var **vpp;
2071
2072 /*
2073 * PS1 depends on uid
2074 */
2075#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002076 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002077#else
2078 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002079 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002080#endif
2081 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002082 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002083 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002084 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002085 vp->next = *vpp;
2086 *vpp = vp;
2087 } while (++vp < end);
2088}
2089
2090static struct var **
2091findvar(struct var **vpp, const char *name)
2092{
2093 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002094 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002095 break;
2096 }
2097 }
2098 return vpp;
2099}
2100
2101/*
2102 * Find the value of a variable. Returns NULL if not set.
2103 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002104static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002105lookupvar(const char *name)
2106{
2107 struct var *v;
2108
2109 v = *findvar(hashvar(name), name);
2110 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002111#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002112 /*
2113 * Dynamic variables are implemented roughly the same way they are
2114 * in bash. Namely, they're "special" so long as they aren't unset.
2115 * As soon as they're unset, they're no longer dynamic, and dynamic
2116 * lookup will no longer happen at that point. -- PFM.
2117 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002118 if (v->flags & VDYNAMIC)
2119 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002120#endif
2121 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002122 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002123 }
2124 return NULL;
2125}
2126
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002127static void reinit_unicode_for_ash(void)
2128{
2129 /* Unicode support should be activated even if LANG is set
2130 * _during_ shell execution, not only if it was set when
2131 * shell was started. Therefore, re-check LANG every time:
2132 */
2133 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2134 || ENABLE_UNICODE_USING_LOCALE
2135 ) {
2136 const char *s = lookupvar("LC_ALL");
2137 if (!s) s = lookupvar("LC_CTYPE");
2138 if (!s) s = lookupvar("LANG");
2139 reinit_unicode(s);
2140 }
2141}
2142
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002143/*
2144 * Search the environment of a builtin command.
2145 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002146static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002147bltinlookup(const char *name)
2148{
2149 struct strlist *sp;
2150
2151 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002152 if (varcmp(sp->text, name) == 0)
2153 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002154 }
2155 return lookupvar(name);
2156}
2157
2158/*
2159 * Same as setvar except that the variable and value are passed in
2160 * the first argument as name=value. Since the first argument will
2161 * be actually stored in the table, it should not be a string that
2162 * will go away.
2163 * Called with interrupts off.
2164 */
2165static void
2166setvareq(char *s, int flags)
2167{
2168 struct var *vp, **vpp;
2169
2170 vpp = hashvar(s);
2171 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2172 vp = *findvar(vpp, s);
2173 if (vp) {
2174 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2175 const char *n;
2176
2177 if (flags & VNOSAVE)
2178 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002179 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002180 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2181 }
2182
2183 if (flags & VNOSET)
2184 return;
2185
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002186 if (vp->var_func && !(flags & VNOFUNC))
2187 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002188
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002189 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2190 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002191
2192 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2193 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002194 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002195 if (flags & VNOSET)
2196 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002197 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002198 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002199 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002200 *vpp = vp;
2201 }
2202 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2203 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002204 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002205 vp->flags = flags;
2206}
2207
2208/*
2209 * Set the value of a variable. The flags argument is ored with the
2210 * flags of the variable. If val is NULL, the variable is unset.
2211 */
2212static void
2213setvar(const char *name, const char *val, int flags)
2214{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002215 const char *q;
2216 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002217 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002218 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002219 size_t vallen;
2220
2221 q = endofname(name);
2222 p = strchrnul(q, '=');
2223 namelen = p - name;
2224 if (!namelen || p != q)
2225 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2226 vallen = 0;
2227 if (val == NULL) {
2228 flags |= VUNSET;
2229 } else {
2230 vallen = strlen(val);
2231 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002232
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002233 INT_OFF;
2234 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002235 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002236 if (val) {
2237 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002238 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002239 }
2240 *p = '\0';
2241 setvareq(nameeq, flags | VNOSAVE);
2242 INT_ON;
2243}
2244
Denys Vlasenko03dad222010-01-12 23:29:57 +01002245static void FAST_FUNC
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002246setvar0(const char *name, const char *val)
Denys Vlasenko03dad222010-01-12 23:29:57 +01002247{
2248 setvar(name, val, 0);
2249}
2250
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002251#if ENABLE_ASH_GETOPTS
2252/*
2253 * Safe version of setvar, returns 1 on success 0 on failure.
2254 */
2255static int
2256setvarsafe(const char *name, const char *val, int flags)
2257{
2258 int err;
2259 volatile int saveint;
2260 struct jmploc *volatile savehandler = exception_handler;
2261 struct jmploc jmploc;
2262
2263 SAVE_INT(saveint);
2264 if (setjmp(jmploc.loc))
2265 err = 1;
2266 else {
2267 exception_handler = &jmploc;
2268 setvar(name, val, flags);
2269 err = 0;
2270 }
2271 exception_handler = savehandler;
2272 RESTORE_INT(saveint);
2273 return err;
2274}
2275#endif
2276
2277/*
2278 * Unset the specified variable.
2279 */
2280static int
2281unsetvar(const char *s)
2282{
2283 struct var **vpp;
2284 struct var *vp;
2285 int retval;
2286
2287 vpp = findvar(hashvar(s), s);
2288 vp = *vpp;
2289 retval = 2;
2290 if (vp) {
2291 int flags = vp->flags;
2292
2293 retval = 1;
2294 if (flags & VREADONLY)
2295 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002296#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002297 vp->flags &= ~VDYNAMIC;
2298#endif
2299 if (flags & VUNSET)
2300 goto ok;
2301 if ((flags & VSTRFIXED) == 0) {
2302 INT_OFF;
2303 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002304 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002305 *vpp = vp->next;
2306 free(vp);
2307 INT_ON;
2308 } else {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02002309 setvar0(s, NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002310 vp->flags &= ~VEXPORT;
2311 }
2312 ok:
2313 retval = 0;
2314 }
2315 out:
2316 return retval;
2317}
2318
2319/*
2320 * Process a linked list of variable assignments.
2321 */
2322static void
2323listsetvar(struct strlist *list_set_var, int flags)
2324{
2325 struct strlist *lp = list_set_var;
2326
2327 if (!lp)
2328 return;
2329 INT_OFF;
2330 do {
2331 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002332 lp = lp->next;
2333 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002334 INT_ON;
2335}
2336
2337/*
2338 * Generate a list of variables satisfying the given conditions.
2339 */
2340static char **
2341listvars(int on, int off, char ***end)
2342{
2343 struct var **vpp;
2344 struct var *vp;
2345 char **ep;
2346 int mask;
2347
2348 STARTSTACKSTR(ep);
2349 vpp = vartab;
2350 mask = on | off;
2351 do {
2352 for (vp = *vpp; vp; vp = vp->next) {
2353 if ((vp->flags & mask) == on) {
2354 if (ep == stackstrend())
2355 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002356 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002357 }
2358 }
2359 } while (++vpp < vartab + VTABSIZE);
2360 if (ep == stackstrend())
2361 ep = growstackstr();
2362 if (end)
2363 *end = ep;
2364 *ep++ = NULL;
2365 return grabstackstr(ep);
2366}
2367
2368
2369/* ============ Path search helper
2370 *
2371 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002372 * of the path before the first call; path_advance will update
2373 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002374 * the possible path expansions in sequence. If an option (indicated by
2375 * a percent sign) appears in the path entry then the global variable
2376 * pathopt will be set to point to it; otherwise pathopt will be set to
2377 * NULL.
2378 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002379static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002380
2381static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002382path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002383{
2384 const char *p;
2385 char *q;
2386 const char *start;
2387 size_t len;
2388
2389 if (*path == NULL)
2390 return NULL;
2391 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002392 for (p = start; *p && *p != ':' && *p != '%'; p++)
2393 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002394 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2395 while (stackblocksize() < len)
2396 growstackblock();
2397 q = stackblock();
2398 if (p != start) {
2399 memcpy(q, start, p - start);
2400 q += p - start;
2401 *q++ = '/';
2402 }
2403 strcpy(q, name);
2404 pathopt = NULL;
2405 if (*p == '%') {
2406 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002407 while (*p && *p != ':')
2408 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002409 }
2410 if (*p == ':')
2411 *path = p + 1;
2412 else
2413 *path = NULL;
2414 return stalloc(len);
2415}
2416
2417
2418/* ============ Prompt */
2419
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002420static smallint doprompt; /* if set, prompt the user */
2421static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002422
2423#if ENABLE_FEATURE_EDITING
2424static line_input_t *line_input_state;
2425static const char *cmdedit_prompt;
2426static void
2427putprompt(const char *s)
2428{
2429 if (ENABLE_ASH_EXPAND_PRMT) {
2430 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002431 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002432 return;
2433 }
2434 cmdedit_prompt = s;
2435}
2436#else
2437static void
2438putprompt(const char *s)
2439{
2440 out2str(s);
2441}
2442#endif
2443
2444#if ENABLE_ASH_EXPAND_PRMT
2445/* expandstr() needs parsing machinery, so it is far away ahead... */
2446static const char *expandstr(const char *ps);
2447#else
2448#define expandstr(s) s
2449#endif
2450
2451static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002452setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002453{
2454 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002455 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2456
2457 if (!do_set)
2458 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002459
2460 needprompt = 0;
2461
2462 switch (whichprompt) {
2463 case 1:
2464 prompt = ps1val();
2465 break;
2466 case 2:
2467 prompt = ps2val();
2468 break;
2469 default: /* 0 */
2470 prompt = nullstr;
2471 }
2472#if ENABLE_ASH_EXPAND_PRMT
2473 setstackmark(&smark);
2474 stalloc(stackblocksize());
2475#endif
2476 putprompt(expandstr(prompt));
2477#if ENABLE_ASH_EXPAND_PRMT
2478 popstackmark(&smark);
2479#endif
2480}
2481
2482
2483/* ============ The cd and pwd commands */
2484
2485#define CD_PHYSICAL 1
2486#define CD_PRINT 2
2487
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002488static int
2489cdopt(void)
2490{
2491 int flags = 0;
2492 int i, j;
2493
2494 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002495 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002496 if (i != j) {
2497 flags ^= CD_PHYSICAL;
2498 j = i;
2499 }
2500 }
2501
2502 return flags;
2503}
2504
2505/*
2506 * Update curdir (the name of the current directory) in response to a
2507 * cd command.
2508 */
2509static const char *
2510updatepwd(const char *dir)
2511{
2512 char *new;
2513 char *p;
2514 char *cdcomppath;
2515 const char *lim;
2516
2517 cdcomppath = ststrdup(dir);
2518 STARTSTACKSTR(new);
2519 if (*dir != '/') {
2520 if (curdir == nullstr)
2521 return 0;
2522 new = stack_putstr(curdir, new);
2523 }
2524 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002525 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002526 if (*dir != '/') {
2527 if (new[-1] != '/')
2528 USTPUTC('/', new);
2529 if (new > lim && *lim == '/')
2530 lim++;
2531 } else {
2532 USTPUTC('/', new);
2533 cdcomppath++;
2534 if (dir[1] == '/' && dir[2] != '/') {
2535 USTPUTC('/', new);
2536 cdcomppath++;
2537 lim++;
2538 }
2539 }
2540 p = strtok(cdcomppath, "/");
2541 while (p) {
2542 switch (*p) {
2543 case '.':
2544 if (p[1] == '.' && p[2] == '\0') {
2545 while (new > lim) {
2546 STUNPUTC(new);
2547 if (new[-1] == '/')
2548 break;
2549 }
2550 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002551 }
2552 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002553 break;
2554 /* fall through */
2555 default:
2556 new = stack_putstr(p, new);
2557 USTPUTC('/', new);
2558 }
Denys Vlasenko00da72b2015-10-23 18:43:16 +02002559 p = strtok(NULL, "/");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002560 }
2561 if (new > lim)
2562 STUNPUTC(new);
2563 *new = 0;
2564 return stackblock();
2565}
2566
2567/*
2568 * Find out what the current directory is. If we already know the current
2569 * directory, this routine returns immediately.
2570 */
2571static char *
2572getpwd(void)
2573{
Denis Vlasenko01631112007-12-16 17:20:38 +00002574 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002575 return dir ? dir : nullstr;
2576}
2577
2578static void
2579setpwd(const char *val, int setold)
2580{
2581 char *oldcur, *dir;
2582
2583 oldcur = dir = curdir;
2584
2585 if (setold) {
2586 setvar("OLDPWD", oldcur, VEXPORT);
2587 }
2588 INT_OFF;
2589 if (physdir != nullstr) {
2590 if (physdir != oldcur)
2591 free(physdir);
2592 physdir = nullstr;
2593 }
2594 if (oldcur == val || !val) {
2595 char *s = getpwd();
2596 physdir = s;
2597 if (!val)
2598 dir = s;
2599 } else
2600 dir = ckstrdup(val);
2601 if (oldcur != dir && oldcur != nullstr) {
2602 free(oldcur);
2603 }
2604 curdir = dir;
2605 INT_ON;
2606 setvar("PWD", dir, VEXPORT);
2607}
2608
2609static void hashcd(void);
2610
2611/*
2612 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2613 * know that the current directory has changed.
2614 */
2615static int
2616docd(const char *dest, int flags)
2617{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002618 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002619 int err;
2620
2621 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2622
2623 INT_OFF;
2624 if (!(flags & CD_PHYSICAL)) {
2625 dir = updatepwd(dest);
2626 if (dir)
2627 dest = dir;
2628 }
2629 err = chdir(dest);
2630 if (err)
2631 goto out;
2632 setpwd(dir, 1);
2633 hashcd();
2634 out:
2635 INT_ON;
2636 return err;
2637}
2638
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002639static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002640cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002641{
2642 const char *dest;
2643 const char *path;
2644 const char *p;
2645 char c;
2646 struct stat statb;
2647 int flags;
2648
2649 flags = cdopt();
2650 dest = *argptr;
2651 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002652 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002653 else if (LONE_DASH(dest)) {
2654 dest = bltinlookup("OLDPWD");
2655 flags |= CD_PRINT;
2656 }
2657 if (!dest)
2658 dest = nullstr;
2659 if (*dest == '/')
2660 goto step7;
2661 if (*dest == '.') {
2662 c = dest[1];
2663 dotdot:
2664 switch (c) {
2665 case '\0':
2666 case '/':
2667 goto step6;
2668 case '.':
2669 c = dest[2];
2670 if (c != '.')
2671 goto dotdot;
2672 }
2673 }
2674 if (!*dest)
2675 dest = ".";
2676 path = bltinlookup("CDPATH");
2677 if (!path) {
2678 step6:
2679 step7:
2680 p = dest;
2681 goto docd;
2682 }
2683 do {
2684 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002685 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002686 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2687 if (c && c != ':')
2688 flags |= CD_PRINT;
2689 docd:
2690 if (!docd(p, flags))
2691 goto out;
2692 break;
2693 }
2694 } while (path);
2695 ash_msg_and_raise_error("can't cd to %s", dest);
2696 /* NOTREACHED */
2697 out:
2698 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002699 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002700 return 0;
2701}
2702
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002703static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002704pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002705{
2706 int flags;
2707 const char *dir = curdir;
2708
2709 flags = cdopt();
2710 if (flags) {
2711 if (physdir == nullstr)
2712 setpwd(dir, 0);
2713 dir = physdir;
2714 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002715 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002716 return 0;
2717}
2718
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002719
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002720/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002721
Denis Vlasenko834dee72008-10-07 09:18:30 +00002722
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002723#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002724
Eric Andersenc470f442003-07-28 09:56:35 +00002725/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002726#define CWORD 0 /* character is nothing special */
2727#define CNL 1 /* newline character */
2728#define CBACK 2 /* a backslash character */
2729#define CSQUOTE 3 /* single quote */
2730#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002731#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002732#define CBQUOTE 6 /* backwards single quote */
2733#define CVAR 7 /* a dollar sign */
2734#define CENDVAR 8 /* a '}' character */
2735#define CLP 9 /* a left paren in arithmetic */
2736#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002737#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002738#define CCTL 12 /* like CWORD, except it must be escaped */
2739#define CSPCL 13 /* these terminate a word */
2740#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002741
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002742#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002743#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002744# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002745#endif
2746
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002747#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002748
Mike Frysinger98c52642009-04-02 10:02:37 +00002749#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002750# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002751#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002752# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002753#endif
Denys Vlasenko068d3862009-11-29 01:41:11 +01002754static const uint16_t S_I_T[] = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002755#if ENABLE_ASH_ALIAS
2756 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2757#endif
2758 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2759 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2760 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2761 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2762 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2763 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2764 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2765 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2766 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2767 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2768 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002769#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002770 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2771 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2772 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2773#endif
2774#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002775};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002776/* Constants below must match table above */
2777enum {
2778#if ENABLE_ASH_ALIAS
2779 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2780#endif
2781 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2782 CNL_CNL_CNL_CNL , /* 2 */
2783 CWORD_CCTL_CCTL_CWORD , /* 3 */
2784 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2785 CVAR_CVAR_CWORD_CVAR , /* 5 */
2786 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2787 CSPCL_CWORD_CWORD_CLP , /* 7 */
2788 CSPCL_CWORD_CWORD_CRP , /* 8 */
2789 CBACK_CBACK_CCTL_CBACK , /* 9 */
2790 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2791 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2792 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2793 CWORD_CWORD_CWORD_CWORD , /* 13 */
2794 CCTL_CCTL_CCTL_CCTL , /* 14 */
2795};
Eric Andersen2870d962001-07-02 17:27:21 +00002796
Denys Vlasenkocd716832009-11-28 22:14:02 +01002797/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2798 * caller must ensure proper cast on it if c is *char_ptr!
2799 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002800/* Values for syntax param */
2801#define BASESYNTAX 0 /* not in quotes */
2802#define DQSYNTAX 1 /* in double quotes */
2803#define SQSYNTAX 2 /* in single quotes */
2804#define ARISYNTAX 3 /* in arithmetic */
2805#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002806
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002807#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002808
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002809static int
2810SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002811{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00002812 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Denys Vlasenkocd716832009-11-28 22:14:02 +01002813# if ENABLE_ASH_ALIAS
2814 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002815 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2816 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2817 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2818 11, 3 /* "}~" */
2819 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002820# else
2821 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002822 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2823 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2824 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2825 10, 2 /* "}~" */
2826 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002827# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002828 const char *s;
2829 int indx;
2830
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002831 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002832 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002833# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002834 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002835 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002836 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002837# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002838 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002839 /* Cast is purely for paranoia here,
2840 * just in case someone passed signed char to us */
2841 if ((unsigned char)c >= CTL_FIRST
2842 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002843 ) {
2844 return CCTL;
2845 }
2846 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002847 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002848 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002849 indx = syntax_index_table[s - spec_symbls];
2850 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002851 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002852}
2853
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002854#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002855
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002856static const uint8_t syntax_index_table[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002857 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002858 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2859 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2860 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2861 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2862 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2868 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2869 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2872 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2873 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2891 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2892 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2893 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2894 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2895 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2896 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2897 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2898 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2899 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2900 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2901 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2902 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2903 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2904 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2905 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2906 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2907 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2908 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2909 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2910 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2917 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2918 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2919 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2920 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2921 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2922 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2923 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2924 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2925 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2926 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2950 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2951 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2952 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2954 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2955 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2956 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2959 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2983 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2984 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2985 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2986 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2987 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2988 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2989 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2990 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2991 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2992 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2993 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2994 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2995 /* 137 */ CWORD_CWORD_CWORD_CWORD,
2996 /* 138 */ CWORD_CWORD_CWORD_CWORD,
2997 /* 139 */ CWORD_CWORD_CWORD_CWORD,
2998 /* 140 */ CWORD_CWORD_CWORD_CWORD,
2999 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003114 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003115# if ENABLE_ASH_ALIAS
3116 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3117# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003118};
3119
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003120# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003121
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003122#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003123
Eric Andersen2870d962001-07-02 17:27:21 +00003124
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003125/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003126
Denis Vlasenko131ae172007-02-18 13:00:19 +00003127#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003128
3129#define ALIASINUSE 1
3130#define ALIASDEAD 2
3131
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003132struct alias {
3133 struct alias *next;
3134 char *name;
3135 char *val;
3136 int flag;
3137};
3138
Denis Vlasenko01631112007-12-16 17:20:38 +00003139
3140static struct alias **atab; // [ATABSIZE];
3141#define INIT_G_alias() do { \
3142 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3143} while (0)
3144
Eric Andersen2870d962001-07-02 17:27:21 +00003145
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003146static struct alias **
3147__lookupalias(const char *name) {
3148 unsigned int hashval;
3149 struct alias **app;
3150 const char *p;
3151 unsigned int ch;
3152
3153 p = name;
3154
3155 ch = (unsigned char)*p;
3156 hashval = ch << 4;
3157 while (ch) {
3158 hashval += ch;
3159 ch = (unsigned char)*++p;
3160 }
3161 app = &atab[hashval % ATABSIZE];
3162
3163 for (; *app; app = &(*app)->next) {
3164 if (strcmp(name, (*app)->name) == 0) {
3165 break;
3166 }
3167 }
3168
3169 return app;
3170}
3171
3172static struct alias *
3173lookupalias(const char *name, int check)
3174{
3175 struct alias *ap = *__lookupalias(name);
3176
3177 if (check && ap && (ap->flag & ALIASINUSE))
3178 return NULL;
3179 return ap;
3180}
3181
3182static struct alias *
3183freealias(struct alias *ap)
3184{
3185 struct alias *next;
3186
3187 if (ap->flag & ALIASINUSE) {
3188 ap->flag |= ALIASDEAD;
3189 return ap;
3190 }
3191
3192 next = ap->next;
3193 free(ap->name);
3194 free(ap->val);
3195 free(ap);
3196 return next;
3197}
Eric Andersencb57d552001-06-28 07:25:16 +00003198
Eric Andersenc470f442003-07-28 09:56:35 +00003199static void
3200setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003201{
3202 struct alias *ap, **app;
3203
3204 app = __lookupalias(name);
3205 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003206 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003207 if (ap) {
3208 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003209 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003210 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003211 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003212 ap->flag &= ~ALIASDEAD;
3213 } else {
3214 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003215 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003216 ap->name = ckstrdup(name);
3217 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003218 /*ap->flag = 0; - ckzalloc did it */
3219 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003220 *app = ap;
3221 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003222 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003223}
3224
Eric Andersenc470f442003-07-28 09:56:35 +00003225static int
3226unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003227{
Eric Andersencb57d552001-06-28 07:25:16 +00003228 struct alias **app;
3229
3230 app = __lookupalias(name);
3231
3232 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003233 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003234 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003235 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003236 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003237 }
3238
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003239 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003240}
3241
Eric Andersenc470f442003-07-28 09:56:35 +00003242static void
3243rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003244{
Eric Andersencb57d552001-06-28 07:25:16 +00003245 struct alias *ap, **app;
3246 int i;
3247
Denis Vlasenkob012b102007-02-19 22:43:01 +00003248 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003249 for (i = 0; i < ATABSIZE; i++) {
3250 app = &atab[i];
3251 for (ap = *app; ap; ap = *app) {
3252 *app = freealias(*app);
3253 if (ap == *app) {
3254 app = &ap->next;
3255 }
3256 }
3257 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003258 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003259}
3260
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003261static void
3262printalias(const struct alias *ap)
3263{
3264 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3265}
3266
Eric Andersencb57d552001-06-28 07:25:16 +00003267/*
3268 * TODO - sort output
3269 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003270static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003271aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003272{
3273 char *n, *v;
3274 int ret = 0;
3275 struct alias *ap;
3276
Denis Vlasenko68404f12008-03-17 09:00:54 +00003277 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003278 int i;
3279
Denis Vlasenko68404f12008-03-17 09:00:54 +00003280 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003281 for (ap = atab[i]; ap; ap = ap->next) {
3282 printalias(ap);
3283 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003284 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003285 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003286 }
3287 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003288 v = strchr(n+1, '=');
3289 if (v == NULL) { /* n+1: funny ksh stuff */
3290 ap = *__lookupalias(n);
3291 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003292 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003293 ret = 1;
3294 } else
3295 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003296 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003297 *v++ = '\0';
3298 setalias(n, v);
3299 }
3300 }
3301
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003302 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003303}
3304
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003305static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003306unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003307{
3308 int i;
3309
3310 while ((i = nextopt("a")) != '\0') {
3311 if (i == 'a') {
3312 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003313 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003314 }
3315 }
3316 for (i = 0; *argptr; argptr++) {
3317 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003318 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003319 i = 1;
3320 }
3321 }
3322
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003323 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003324}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003325
Denis Vlasenko131ae172007-02-18 13:00:19 +00003326#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003327
Eric Andersenc470f442003-07-28 09:56:35 +00003328
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003329/* ============ jobs.c */
3330
3331/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003332#define FORK_FG 0
3333#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003334#define FORK_NOJOB 2
3335
3336/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003337#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3338#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3339#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denys Vlasenko9c541002015-10-07 15:44:36 +02003340#define SHOW_STDERR 0x08 /* print to stderr (else stdout) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003341
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003342/*
3343 * A job structure contains information about a job. A job is either a
3344 * single process or a set of processes contained in a pipeline. In the
3345 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3346 * array of pids.
3347 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003348struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003349 pid_t ps_pid; /* process id */
3350 int ps_status; /* last process status from wait() */
3351 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003352};
3353
3354struct job {
3355 struct procstat ps0; /* status of process */
3356 struct procstat *ps; /* status or processes when more than one */
3357#if JOBS
3358 int stopstatus; /* status of a stopped job */
3359#endif
3360 uint32_t
3361 nprocs: 16, /* number of processes */
3362 state: 8,
3363#define JOBRUNNING 0 /* at least one proc running */
3364#define JOBSTOPPED 1 /* all procs are stopped */
3365#define JOBDONE 2 /* all procs are completed */
3366#if JOBS
3367 sigint: 1, /* job was killed by SIGINT */
3368 jobctl: 1, /* job running under job control */
3369#endif
3370 waited: 1, /* true if this entry has been waited for */
3371 used: 1, /* true if this entry is in used */
3372 changed: 1; /* true if status has changed */
3373 struct job *prev_job; /* previous job */
3374};
3375
Denis Vlasenko68404f12008-03-17 09:00:54 +00003376static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003377static int forkshell(struct job *, union node *, int);
3378static int waitforjob(struct job *);
3379
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003380#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003381enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003382#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003383#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003384static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003385static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003386#endif
3387
3388/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003389 * Ignore a signal.
3390 */
3391static void
3392ignoresig(int signo)
3393{
3394 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3395 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3396 /* No, need to do it */
3397 signal(signo, SIG_IGN);
3398 }
3399 sigmode[signo - 1] = S_HARD_IGN;
3400}
3401
3402/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003403 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003404 */
3405static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003406signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003407{
3408 gotsig[signo - 1] = 1;
3409
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003410 if (signo == SIGINT && !trap[SIGINT]) {
3411 if (!suppress_int) {
3412 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003413 raise_interrupt(); /* does not return */
3414 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003415 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003416 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003417 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003418 }
3419}
3420
3421/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003422 * Set the signal handler for the specified signal. The routine figures
3423 * out what it should be set to.
3424 */
3425static void
3426setsignal(int signo)
3427{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003428 char *t;
3429 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003430 struct sigaction act;
3431
3432 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003433 new_act = S_DFL;
3434 if (t != NULL) { /* trap for this sig is set */
3435 new_act = S_CATCH;
3436 if (t[0] == '\0') /* trap is "": ignore this sig */
3437 new_act = S_IGN;
3438 }
3439
3440 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003441 switch (signo) {
3442 case SIGINT:
3443 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003444 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003445 break;
3446 case SIGQUIT:
3447#if DEBUG
3448 if (debug)
3449 break;
3450#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003451 /* man bash:
3452 * "In all cases, bash ignores SIGQUIT. Non-builtin
3453 * commands run by bash have signal handlers
3454 * set to the values inherited by the shell
3455 * from its parent". */
3456 new_act = S_IGN;
3457 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003458 case SIGTERM:
3459 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003460 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003461 break;
3462#if JOBS
3463 case SIGTSTP:
3464 case SIGTTOU:
3465 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003466 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003467 break;
3468#endif
3469 }
3470 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003471//TODO: if !rootshell, we reset SIGQUIT to DFL,
3472//whereas we have to restore it to what shell got on entry
3473//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003474
3475 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003476 cur_act = *t;
3477 if (cur_act == 0) {
3478 /* current setting is not yet known */
3479 if (sigaction(signo, NULL, &act)) {
3480 /* pretend it worked; maybe we should give a warning,
3481 * but other shells don't. We don't alter sigmode,
3482 * so we retry every time.
3483 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003484 return;
3485 }
3486 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003487 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003488 if (mflag
3489 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3490 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003491 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003492 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003493 }
3494 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003495 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003497
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003498 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003499 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003500 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003501 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003502 break;
3503 case S_IGN:
3504 act.sa_handler = SIG_IGN;
3505 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003506 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003507
3508 /* flags and mask matter only if !DFL and !IGN, but we do it
3509 * for all cases for more deterministic behavior:
3510 */
3511 act.sa_flags = 0;
3512 sigfillset(&act.sa_mask);
3513
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003514 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003515
3516 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003517}
3518
3519/* mode flags for set_curjob */
3520#define CUR_DELETE 2
3521#define CUR_RUNNING 1
3522#define CUR_STOPPED 0
3523
3524/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003525#define DOWAIT_NONBLOCK WNOHANG
3526#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003527
3528#if JOBS
3529/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003530static int initialpgrp; //references:2
3531static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003532#endif
3533/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003534static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003535/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003536static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003537/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003538static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003539/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003540static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003541
3542static void
3543set_curjob(struct job *jp, unsigned mode)
3544{
3545 struct job *jp1;
3546 struct job **jpp, **curp;
3547
3548 /* first remove from list */
3549 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003550 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003551 jp1 = *jpp;
3552 if (jp1 == jp)
3553 break;
3554 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003555 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003556 *jpp = jp1->prev_job;
3557
3558 /* Then re-insert in correct position */
3559 jpp = curp;
3560 switch (mode) {
3561 default:
3562#if DEBUG
3563 abort();
3564#endif
3565 case CUR_DELETE:
3566 /* job being deleted */
3567 break;
3568 case CUR_RUNNING:
3569 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003570 * put after all stopped jobs.
3571 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003572 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003573 jp1 = *jpp;
3574#if JOBS
3575 if (!jp1 || jp1->state != JOBSTOPPED)
3576#endif
3577 break;
3578 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003579 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003580 /* FALLTHROUGH */
3581#if JOBS
3582 case CUR_STOPPED:
3583#endif
3584 /* newly stopped job - becomes curjob */
3585 jp->prev_job = *jpp;
3586 *jpp = jp;
3587 break;
3588 }
3589}
3590
3591#if JOBS || DEBUG
3592static int
3593jobno(const struct job *jp)
3594{
3595 return jp - jobtab + 1;
3596}
3597#endif
3598
3599/*
3600 * Convert a job name to a job structure.
3601 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003602#if !JOBS
3603#define getjob(name, getctl) getjob(name)
3604#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003605static struct job *
3606getjob(const char *name, int getctl)
3607{
3608 struct job *jp;
3609 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003610 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003611 unsigned num;
3612 int c;
3613 const char *p;
3614 char *(*match)(const char *, const char *);
3615
3616 jp = curjob;
3617 p = name;
3618 if (!p)
3619 goto currentjob;
3620
3621 if (*p != '%')
3622 goto err;
3623
3624 c = *++p;
3625 if (!c)
3626 goto currentjob;
3627
3628 if (!p[1]) {
3629 if (c == '+' || c == '%') {
3630 currentjob:
3631 err_msg = "No current job";
3632 goto check;
3633 }
3634 if (c == '-') {
3635 if (jp)
3636 jp = jp->prev_job;
3637 err_msg = "No previous job";
3638 check:
3639 if (!jp)
3640 goto err;
3641 goto gotit;
3642 }
3643 }
3644
3645 if (is_number(p)) {
3646 num = atoi(p);
Denys Vlasenko07f7ea72014-09-08 17:21:52 +02003647 if (num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003648 jp = jobtab + num - 1;
3649 if (jp->used)
3650 goto gotit;
3651 goto err;
3652 }
3653 }
3654
3655 match = prefix;
3656 if (*p == '?') {
3657 match = strstr;
3658 p++;
3659 }
3660
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003661 found = NULL;
3662 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003663 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003664 if (found)
3665 goto err;
3666 found = jp;
3667 err_msg = "%s: ambiguous";
3668 }
3669 jp = jp->prev_job;
3670 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003671 if (!found)
3672 goto err;
3673 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003674
3675 gotit:
3676#if JOBS
3677 err_msg = "job %s not created under job control";
3678 if (getctl && jp->jobctl == 0)
3679 goto err;
3680#endif
3681 return jp;
3682 err:
3683 ash_msg_and_raise_error(err_msg, name);
3684}
3685
3686/*
3687 * Mark a job structure as unused.
3688 */
3689static void
3690freejob(struct job *jp)
3691{
3692 struct procstat *ps;
3693 int i;
3694
3695 INT_OFF;
3696 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003697 if (ps->ps_cmd != nullstr)
3698 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003699 }
3700 if (jp->ps != &jp->ps0)
3701 free(jp->ps);
3702 jp->used = 0;
3703 set_curjob(jp, CUR_DELETE);
3704 INT_ON;
3705}
3706
3707#if JOBS
3708static void
3709xtcsetpgrp(int fd, pid_t pgrp)
3710{
3711 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003712 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003713}
3714
3715/*
3716 * Turn job control on and off.
3717 *
3718 * Note: This code assumes that the third arg to ioctl is a character
3719 * pointer, which is true on Berkeley systems but not System V. Since
3720 * System V doesn't have job control yet, this isn't a problem now.
3721 *
3722 * Called with interrupts off.
3723 */
3724static void
3725setjobctl(int on)
3726{
3727 int fd;
3728 int pgrp;
3729
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003730 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003731 return;
3732 if (on) {
3733 int ofd;
3734 ofd = fd = open(_PATH_TTY, O_RDWR);
3735 if (fd < 0) {
3736 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3737 * That sometimes helps to acquire controlling tty.
3738 * Obviously, a workaround for bugs when someone
3739 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003740 fd = 2;
3741 while (!isatty(fd))
3742 if (--fd < 0)
3743 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003744 }
3745 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003746 if (ofd >= 0)
3747 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003748 if (fd < 0)
3749 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003750 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003751 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003752 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003753 pgrp = tcgetpgrp(fd);
3754 if (pgrp < 0) {
3755 out:
3756 ash_msg("can't access tty; job control turned off");
3757 mflag = on = 0;
3758 goto close;
3759 }
3760 if (pgrp == getpgrp())
3761 break;
3762 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003763 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003764 initialpgrp = pgrp;
3765
3766 setsignal(SIGTSTP);
3767 setsignal(SIGTTOU);
3768 setsignal(SIGTTIN);
3769 pgrp = rootpid;
3770 setpgid(0, pgrp);
3771 xtcsetpgrp(fd, pgrp);
3772 } else {
3773 /* turning job control off */
3774 fd = ttyfd;
3775 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003776 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003777 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003778 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003779 setpgid(0, pgrp);
3780 setsignal(SIGTSTP);
3781 setsignal(SIGTTOU);
3782 setsignal(SIGTTIN);
3783 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003784 if (fd >= 0)
3785 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003786 fd = -1;
3787 }
3788 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003789 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003790}
3791
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003792static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003793killcmd(int argc, char **argv)
3794{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003795 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003796 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003797 do {
3798 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003799 /*
3800 * "kill %N" - job kill
3801 * Converting to pgrp / pid kill
3802 */
3803 struct job *jp;
3804 char *dst;
3805 int j, n;
3806
3807 jp = getjob(argv[i], 0);
3808 /*
3809 * In jobs started under job control, we signal
3810 * entire process group by kill -PGRP_ID.
3811 * This happens, f.e., in interactive shell.
3812 *
3813 * Otherwise, we signal each child via
3814 * kill PID1 PID2 PID3.
3815 * Testcases:
3816 * sh -c 'sleep 1|sleep 1 & kill %1'
3817 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3818 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3819 */
3820 n = jp->nprocs; /* can't be 0 (I hope) */
3821 if (jp->jobctl)
3822 n = 1;
3823 dst = alloca(n * sizeof(int)*4);
3824 argv[i] = dst;
3825 for (j = 0; j < n; j++) {
3826 struct procstat *ps = &jp->ps[j];
3827 /* Skip non-running and not-stopped members
3828 * (i.e. dead members) of the job
3829 */
3830 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3831 continue;
3832 /*
3833 * kill_main has matching code to expect
3834 * leading space. Needed to not confuse
3835 * negative pids with "kill -SIGNAL_NO" syntax
3836 */
3837 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3838 }
3839 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003840 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003841 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003842 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003843 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003844}
3845
3846static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003847showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003848{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003849 struct procstat *ps;
3850 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003851
Denys Vlasenko285ad152009-12-04 23:02:27 +01003852 psend = jp->ps + jp->nprocs;
3853 for (ps = jp->ps + 1; ps < psend; ps++)
3854 printf(" | %s", ps->ps_cmd);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003855 newline_and_flush(stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003856 flush_stdout_stderr();
3857}
3858
3859
3860static int
3861restartjob(struct job *jp, int mode)
3862{
3863 struct procstat *ps;
3864 int i;
3865 int status;
3866 pid_t pgid;
3867
3868 INT_OFF;
3869 if (jp->state == JOBDONE)
3870 goto out;
3871 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003872 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003873 if (mode == FORK_FG)
3874 xtcsetpgrp(ttyfd, pgid);
3875 killpg(pgid, SIGCONT);
3876 ps = jp->ps;
3877 i = jp->nprocs;
3878 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003879 if (WIFSTOPPED(ps->ps_status)) {
3880 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003881 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003882 ps++;
3883 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003884 out:
3885 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3886 INT_ON;
3887 return status;
3888}
3889
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003890static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003891fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003892{
3893 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003894 int mode;
3895 int retval;
3896
3897 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3898 nextopt(nullstr);
3899 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003900 do {
3901 jp = getjob(*argv, 1);
3902 if (mode == FORK_BG) {
3903 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003904 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003905 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003906 out1str(jp->ps[0].ps_cmd);
3907 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003908 retval = restartjob(jp, mode);
3909 } while (*argv && *++argv);
3910 return retval;
3911}
3912#endif
3913
3914static int
Denys Vlasenko9c541002015-10-07 15:44:36 +02003915sprint_status48(char *s, int status, int sigonly)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003916{
3917 int col;
3918 int st;
3919
3920 col = 0;
3921 if (!WIFEXITED(status)) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003922 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003923 st = WSTOPSIG(status);
3924 else
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003925 st = WTERMSIG(status);
3926 if (sigonly) {
3927 if (st == SIGINT || st == SIGPIPE)
3928 goto out;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003929 if (JOBS && WIFSTOPPED(status))
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003930 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003931 }
3932 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003933//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003934 col = fmtstr(s, 32, strsignal(st));
3935 if (WCOREDUMP(status)) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02003936 strcpy(s + col, " (core dumped)");
3937 col += sizeof(" (core dumped)")-1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003938 }
3939 } else if (!sigonly) {
3940 st = WEXITSTATUS(status);
Denys Vlasenko9c541002015-10-07 15:44:36 +02003941 col = fmtstr(s, 16, (st ? "Done(%d)" : "Done"), st);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003942 }
3943 out:
3944 return col;
3945}
3946
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003947static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003948dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003949{
3950 int pid;
3951 int status;
3952 struct job *jp;
3953 struct job *thisjob;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003954
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003955 TRACE(("dowait(0x%x) called\n", wait_flags));
3956
3957 /* Do a wait system call. If job control is compiled in, we accept
3958 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3959 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003960 if (doing_jobctl)
3961 wait_flags |= WUNTRACED;
3962 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003963 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3964 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003965 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003966 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003967
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003968 INT_OFF;
3969 thisjob = NULL;
3970 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003971 int jobstate;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003972 struct procstat *ps;
3973 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003974 if (jp->state == JOBDONE)
3975 continue;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003976 jobstate = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003977 ps = jp->ps;
3978 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003979 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003980 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003981 TRACE(("Job %d: changing status of proc %d "
3982 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003983 jobno(jp), pid, ps->ps_status, status));
3984 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003985 thisjob = jp;
3986 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003987 if (ps->ps_status == -1)
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003988 jobstate = JOBRUNNING;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003989#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003990 if (jobstate == JOBRUNNING)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003991 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003992 if (WIFSTOPPED(ps->ps_status)) {
3993 jp->stopstatus = ps->ps_status;
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003994 jobstate = JOBSTOPPED;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003995 }
3996#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01003997 } while (++ps < psend);
Denys Vlasenko4700fb52015-10-09 15:40:13 +02003998 if (!thisjob)
3999 continue;
4000
4001 /* Found the job where one of its processes changed its state.
4002 * Is there at least one live and running process in this job? */
4003 if (jobstate != JOBRUNNING) {
4004 /* No. All live processes in the job are stopped
4005 * (JOBSTOPPED) or there are no live processes (JOBDONE)
4006 */
4007 thisjob->changed = 1;
4008 if (thisjob->state != jobstate) {
4009 TRACE(("Job %d: changing state from %d to %d\n",
4010 jobno(thisjob), thisjob->state, jobstate));
4011 thisjob->state = jobstate;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004012#if JOBS
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004013 if (jobstate == JOBSTOPPED)
4014 set_curjob(thisjob, CUR_STOPPED);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004015#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004016 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004017 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004018 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004019 }
Denys Vlasenko4700fb52015-10-09 15:40:13 +02004020 /* The process wasn't found in job list */
4021 if (JOBS && !WIFSTOPPED(status))
4022 jobless--;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004023 out:
4024 INT_ON;
4025
4026 if (thisjob && thisjob == job) {
4027 char s[48 + 1];
4028 int len;
4029
Denys Vlasenko9c541002015-10-07 15:44:36 +02004030 len = sprint_status48(s, status, 1);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004031 if (len) {
4032 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004033 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004034 out2str(s);
4035 }
4036 }
4037 return pid;
4038}
4039
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004040static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004041blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004042{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004043 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004044 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004045 raise_exception(EXSIG);
4046 return pid;
4047}
4048
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004049#if JOBS
4050static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004051showjob(struct job *jp, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004052{
4053 struct procstat *ps;
4054 struct procstat *psend;
4055 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004056 int indent_col;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004057 char s[16 + 16 + 48];
4058 FILE *out = (mode & SHOW_STDERR ? stderr : stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004059
4060 ps = jp->ps;
4061
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004062 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004063 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004064 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004065 return;
4066 }
4067
4068 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004069 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004070
4071 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004072 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004074 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004075
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004076 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004077 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004078
4079 psend = ps + jp->nprocs;
4080
4081 if (jp->state == JOBRUNNING) {
4082 strcpy(s + col, "Running");
4083 col += sizeof("Running") - 1;
4084 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004085 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004086 if (jp->state == JOBSTOPPED)
4087 status = jp->stopstatus;
Denys Vlasenko9c541002015-10-07 15:44:36 +02004088 col += sprint_status48(s + col, status, 0);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004089 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004090 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004091
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004092 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4093 * or prints several "PID | <cmdN>" lines,
4094 * depending on SHOW_PIDS bit.
4095 * We do not print status of individual processes
4096 * between PID and <cmdN>. bash does it, but not very well:
4097 * first line shows overall job status, not process status,
4098 * making it impossible to know 1st process status.
4099 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004100 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004101 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004102 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004103 s[0] = '\0';
4104 col = 33;
4105 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004106 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004107 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004108 fprintf(out, "%s%*c%s%s",
4109 s,
4110 33 - col >= 0 ? 33 - col : 0, ' ',
4111 ps == jp->ps ? "" : "| ",
4112 ps->ps_cmd
4113 );
4114 } while (++ps != psend);
Denys Vlasenko9c541002015-10-07 15:44:36 +02004115 newline_and_flush(out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004116
4117 jp->changed = 0;
4118
4119 if (jp->state == JOBDONE) {
4120 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4121 freejob(jp);
4122 }
4123}
4124
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004125/*
4126 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4127 * statuses have changed since the last call to showjobs.
4128 */
4129static void
Denys Vlasenko9c541002015-10-07 15:44:36 +02004130showjobs(int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004131{
4132 struct job *jp;
4133
Denys Vlasenko883cea42009-07-11 15:31:59 +02004134 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004135
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004136 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004137 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004138 continue;
4139
4140 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004141 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004142 showjob(jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004143 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004144 }
4145}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004146
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004147static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004148jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004149{
4150 int mode, m;
4151
4152 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004153 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004154 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004155 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004156 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004157 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004158 }
4159
4160 argv = argptr;
4161 if (*argv) {
4162 do
Denys Vlasenko9c541002015-10-07 15:44:36 +02004163 showjob(getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004164 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004165 } else {
Denys Vlasenko9c541002015-10-07 15:44:36 +02004166 showjobs(mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004167 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004168
4169 return 0;
4170}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004171#endif /* JOBS */
4172
Michael Abbott359da5e2009-12-04 23:03:29 +01004173/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004174static int
4175getstatus(struct job *job)
4176{
4177 int status;
4178 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004179 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004180
Michael Abbott359da5e2009-12-04 23:03:29 +01004181 /* Fetch last member's status */
4182 ps = job->ps + job->nprocs - 1;
4183 status = ps->ps_status;
4184 if (pipefail) {
4185 /* "set -o pipefail" mode: use last _nonzero_ status */
4186 while (status == 0 && --ps >= job->ps)
4187 status = ps->ps_status;
4188 }
4189
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004190 retval = WEXITSTATUS(status);
4191 if (!WIFEXITED(status)) {
4192#if JOBS
4193 retval = WSTOPSIG(status);
4194 if (!WIFSTOPPED(status))
4195#endif
4196 {
4197 /* XXX: limits number of signals */
4198 retval = WTERMSIG(status);
4199#if JOBS
4200 if (retval == SIGINT)
4201 job->sigint = 1;
4202#endif
4203 }
4204 retval += 128;
4205 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004206 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004207 jobno(job), job->nprocs, status, retval));
4208 return retval;
4209}
4210
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004211static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004212waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004213{
4214 struct job *job;
4215 int retval;
4216 struct job *jp;
4217
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004218 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004219 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004220
4221 nextopt(nullstr);
4222 retval = 0;
4223
4224 argv = argptr;
4225 if (!*argv) {
4226 /* wait for all jobs */
4227 for (;;) {
4228 jp = curjob;
4229 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004230 if (!jp) /* no running procs */
4231 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004232 if (jp->state == JOBRUNNING)
4233 break;
4234 jp->waited = 1;
4235 jp = jp->prev_job;
4236 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004237 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004238 /* man bash:
4239 * "When bash is waiting for an asynchronous command via
4240 * the wait builtin, the reception of a signal for which a trap
4241 * has been set will cause the wait builtin to return immediately
4242 * with an exit status greater than 128, immediately after which
4243 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004244 *
4245 * blocking_wait_with_raise_on_sig raises signal handlers
4246 * if it gets no pid (pid < 0). However,
4247 * if child sends us a signal *and immediately exits*,
4248 * blocking_wait_with_raise_on_sig gets pid > 0
4249 * and does not handle pending_sig. Check this case: */
4250 if (pending_sig)
4251 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004252 }
4253 }
4254
4255 retval = 127;
4256 do {
4257 if (**argv != '%') {
4258 pid_t pid = number(*argv);
4259 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004260 while (1) {
4261 if (!job)
4262 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004263 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004264 break;
4265 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004266 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004267 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004268 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004269 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004270 /* loop until process terminated or stopped */
4271 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004272 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004273 job->waited = 1;
4274 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004275 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004276 } while (*++argv);
4277
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004278 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004279 return retval;
4280}
4281
4282static struct job *
4283growjobtab(void)
4284{
4285 size_t len;
4286 ptrdiff_t offset;
4287 struct job *jp, *jq;
4288
4289 len = njobs * sizeof(*jp);
4290 jq = jobtab;
4291 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4292
4293 offset = (char *)jp - (char *)jq;
4294 if (offset) {
4295 /* Relocate pointers */
4296 size_t l = len;
4297
4298 jq = (struct job *)((char *)jq + l);
4299 while (l) {
4300 l -= sizeof(*jp);
4301 jq--;
4302#define joff(p) ((struct job *)((char *)(p) + l))
4303#define jmove(p) (p) = (void *)((char *)(p) + offset)
4304 if (joff(jp)->ps == &jq->ps0)
4305 jmove(joff(jp)->ps);
4306 if (joff(jp)->prev_job)
4307 jmove(joff(jp)->prev_job);
4308 }
4309 if (curjob)
4310 jmove(curjob);
4311#undef joff
4312#undef jmove
4313 }
4314
4315 njobs += 4;
4316 jobtab = jp;
4317 jp = (struct job *)((char *)jp + len);
4318 jq = jp + 3;
4319 do {
4320 jq->used = 0;
4321 } while (--jq >= jp);
4322 return jp;
4323}
4324
4325/*
4326 * Return a new job structure.
4327 * Called with interrupts off.
4328 */
4329static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004330makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004331{
4332 int i;
4333 struct job *jp;
4334
4335 for (i = njobs, jp = jobtab; ; jp++) {
4336 if (--i < 0) {
4337 jp = growjobtab();
4338 break;
4339 }
4340 if (jp->used == 0)
4341 break;
4342 if (jp->state != JOBDONE || !jp->waited)
4343 continue;
4344#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004345 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004346 continue;
4347#endif
4348 freejob(jp);
4349 break;
4350 }
4351 memset(jp, 0, sizeof(*jp));
4352#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004353 /* jp->jobctl is a bitfield.
4354 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004355 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004356 jp->jobctl = 1;
4357#endif
4358 jp->prev_job = curjob;
4359 curjob = jp;
4360 jp->used = 1;
4361 jp->ps = &jp->ps0;
4362 if (nprocs > 1) {
4363 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4364 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004365 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004366 jobno(jp)));
4367 return jp;
4368}
4369
4370#if JOBS
4371/*
4372 * Return a string identifying a command (to be printed by the
4373 * jobs command).
4374 */
4375static char *cmdnextc;
4376
4377static void
4378cmdputs(const char *s)
4379{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004380 static const char vstype[VSTYPE + 1][3] = {
4381 "", "}", "-", "+", "?", "=",
4382 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004383 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004384 };
4385
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004386 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004387 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004388 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004389 unsigned char c;
4390 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004391 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004392
Denys Vlasenko46a14772009-12-10 21:27:13 +01004393 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004394 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4395 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004396 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004397 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004398 switch (c) {
4399 case CTLESC:
4400 c = *p++;
4401 break;
4402 case CTLVAR:
4403 subtype = *p++;
4404 if ((subtype & VSTYPE) == VSLENGTH)
4405 str = "${#";
4406 else
4407 str = "${";
Ron Yorston549deab2015-05-18 09:57:51 +02004408 goto dostr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004409 case CTLENDVAR:
4410 str = "\"}" + !(quoted & 1);
4411 quoted >>= 1;
4412 subtype = 0;
4413 goto dostr;
4414 case CTLBACKQ:
4415 str = "$(...)";
4416 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004417#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004418 case CTLARI:
4419 str = "$((";
4420 goto dostr;
4421 case CTLENDARI:
4422 str = "))";
4423 goto dostr;
4424#endif
4425 case CTLQUOTEMARK:
4426 quoted ^= 1;
4427 c = '"';
4428 break;
4429 case '=':
4430 if (subtype == 0)
4431 break;
4432 if ((subtype & VSTYPE) != VSNORMAL)
4433 quoted <<= 1;
4434 str = vstype[subtype & VSTYPE];
4435 if (subtype & VSNUL)
4436 c = ':';
4437 else
4438 goto checkstr;
4439 break;
4440 case '\'':
4441 case '\\':
4442 case '"':
4443 case '$':
4444 /* These can only happen inside quotes */
4445 cc[0] = c;
4446 str = cc;
4447 c = '\\';
4448 break;
4449 default:
4450 break;
4451 }
4452 USTPUTC(c, nextc);
4453 checkstr:
4454 if (!str)
4455 continue;
4456 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004457 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004458 USTPUTC(c, nextc);
4459 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004460 } /* while *p++ not NUL */
4461
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004462 if (quoted & 1) {
4463 USTPUTC('"', nextc);
4464 }
4465 *nextc = 0;
4466 cmdnextc = nextc;
4467}
4468
4469/* cmdtxt() and cmdlist() call each other */
4470static void cmdtxt(union node *n);
4471
4472static void
4473cmdlist(union node *np, int sep)
4474{
4475 for (; np; np = np->narg.next) {
4476 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004477 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004478 cmdtxt(np);
4479 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004480 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004481 }
4482}
4483
4484static void
4485cmdtxt(union node *n)
4486{
4487 union node *np;
4488 struct nodelist *lp;
4489 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004490
4491 if (!n)
4492 return;
4493 switch (n->type) {
4494 default:
4495#if DEBUG
4496 abort();
4497#endif
4498 case NPIPE:
4499 lp = n->npipe.cmdlist;
4500 for (;;) {
4501 cmdtxt(lp->n);
4502 lp = lp->next;
4503 if (!lp)
4504 break;
4505 cmdputs(" | ");
4506 }
4507 break;
4508 case NSEMI:
4509 p = "; ";
4510 goto binop;
4511 case NAND:
4512 p = " && ";
4513 goto binop;
4514 case NOR:
4515 p = " || ";
4516 binop:
4517 cmdtxt(n->nbinary.ch1);
4518 cmdputs(p);
4519 n = n->nbinary.ch2;
4520 goto donode;
4521 case NREDIR:
4522 case NBACKGND:
4523 n = n->nredir.n;
4524 goto donode;
4525 case NNOT:
4526 cmdputs("!");
4527 n = n->nnot.com;
4528 donode:
4529 cmdtxt(n);
4530 break;
4531 case NIF:
4532 cmdputs("if ");
4533 cmdtxt(n->nif.test);
4534 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004535 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004536 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004537 cmdputs("; else ");
4538 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004539 } else {
4540 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004541 }
4542 p = "; fi";
4543 goto dotail;
4544 case NSUBSHELL:
4545 cmdputs("(");
4546 n = n->nredir.n;
4547 p = ")";
4548 goto dotail;
4549 case NWHILE:
4550 p = "while ";
4551 goto until;
4552 case NUNTIL:
4553 p = "until ";
4554 until:
4555 cmdputs(p);
4556 cmdtxt(n->nbinary.ch1);
4557 n = n->nbinary.ch2;
4558 p = "; done";
4559 dodo:
4560 cmdputs("; do ");
4561 dotail:
4562 cmdtxt(n);
4563 goto dotail2;
4564 case NFOR:
4565 cmdputs("for ");
4566 cmdputs(n->nfor.var);
4567 cmdputs(" in ");
4568 cmdlist(n->nfor.args, 1);
4569 n = n->nfor.body;
4570 p = "; done";
4571 goto dodo;
4572 case NDEFUN:
4573 cmdputs(n->narg.text);
4574 p = "() { ... }";
4575 goto dotail2;
4576 case NCMD:
4577 cmdlist(n->ncmd.args, 1);
4578 cmdlist(n->ncmd.redirect, 0);
4579 break;
4580 case NARG:
4581 p = n->narg.text;
4582 dotail2:
4583 cmdputs(p);
4584 break;
4585 case NHERE:
4586 case NXHERE:
4587 p = "<<...";
4588 goto dotail2;
4589 case NCASE:
4590 cmdputs("case ");
4591 cmdputs(n->ncase.expr->narg.text);
4592 cmdputs(" in ");
4593 for (np = n->ncase.cases; np; np = np->nclist.next) {
4594 cmdtxt(np->nclist.pattern);
4595 cmdputs(") ");
4596 cmdtxt(np->nclist.body);
4597 cmdputs(";; ");
4598 }
4599 p = "esac";
4600 goto dotail2;
4601 case NTO:
4602 p = ">";
4603 goto redir;
4604 case NCLOBBER:
4605 p = ">|";
4606 goto redir;
4607 case NAPPEND:
4608 p = ">>";
4609 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004610#if ENABLE_ASH_BASH_COMPAT
4611 case NTO2:
4612#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004613 case NTOFD:
4614 p = ">&";
4615 goto redir;
4616 case NFROM:
4617 p = "<";
4618 goto redir;
4619 case NFROMFD:
4620 p = "<&";
4621 goto redir;
4622 case NFROMTO:
4623 p = "<>";
4624 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004625 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004626 cmdputs(p);
4627 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004628 cmdputs(utoa(n->ndup.dupfd));
4629 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004630 }
4631 n = n->nfile.fname;
4632 goto donode;
4633 }
4634}
4635
4636static char *
4637commandtext(union node *n)
4638{
4639 char *name;
4640
4641 STARTSTACKSTR(cmdnextc);
4642 cmdtxt(n);
4643 name = stackblock();
4644 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4645 name, cmdnextc, cmdnextc));
4646 return ckstrdup(name);
4647}
4648#endif /* JOBS */
4649
4650/*
4651 * Fork off a subshell. If we are doing job control, give the subshell its
4652 * own process group. Jp is a job structure that the job is to be added to.
4653 * N is the command that will be evaluated by the child. Both jp and n may
4654 * be NULL. The mode parameter can be one of the following:
4655 * FORK_FG - Fork off a foreground process.
4656 * FORK_BG - Fork off a background process.
4657 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4658 * process group even if job control is on.
4659 *
4660 * When job control is turned off, background processes have their standard
4661 * input redirected to /dev/null (except for the second and later processes
4662 * in a pipeline).
4663 *
4664 * Called with interrupts off.
4665 */
4666/*
4667 * Clear traps on a fork.
4668 */
4669static void
4670clear_traps(void)
4671{
4672 char **tp;
4673
4674 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004675 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004676 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004677 if (trap_ptr == trap)
4678 free(*tp);
4679 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004680 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004681 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004682 setsignal(tp - trap);
4683 INT_ON;
4684 }
4685 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004686 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004687}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004688
4689/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004690static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004691
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004692/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004693static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004694forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004695{
4696 int oldlvl;
4697
4698 TRACE(("Child shell %d\n", getpid()));
4699 oldlvl = shlvl;
4700 shlvl++;
4701
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004702 /* man bash: "Non-builtin commands run by bash have signal handlers
4703 * set to the values inherited by the shell from its parent".
4704 * Do we do it correctly? */
4705
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004706 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004707
4708 if (mode == FORK_NOJOB /* is it `xxx` ? */
4709 && n && n->type == NCMD /* is it single cmd? */
4710 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004711 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004712 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4713 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4714 ) {
4715 TRACE(("Trap hack\n"));
4716 /* Awful hack for `trap` or $(trap).
4717 *
4718 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4719 * contains an example where "trap" is executed in a subshell:
4720 *
4721 * save_traps=$(trap)
4722 * ...
4723 * eval "$save_traps"
4724 *
4725 * Standard does not say that "trap" in subshell shall print
4726 * parent shell's traps. It only says that its output
4727 * must have suitable form, but then, in the above example
4728 * (which is not supposed to be normative), it implies that.
4729 *
4730 * bash (and probably other shell) does implement it
4731 * (traps are reset to defaults, but "trap" still shows them),
4732 * but as a result, "trap" logic is hopelessly messed up:
4733 *
4734 * # trap
4735 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4736 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4737 * # true | trap <--- trap is in subshell - no output (ditto)
4738 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4739 * trap -- 'echo Ho' SIGWINCH
4740 * # echo `(trap)` <--- in subshell in subshell - output
4741 * trap -- 'echo Ho' SIGWINCH
4742 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4743 * trap -- 'echo Ho' SIGWINCH
4744 *
4745 * The rules when to forget and when to not forget traps
4746 * get really complex and nonsensical.
4747 *
4748 * Our solution: ONLY bare $(trap) or `trap` is special.
4749 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004750 /* Save trap handler strings for trap builtin to print */
Ron Yorstond840c5d2015-07-19 23:05:20 +02004751 trap_ptr = xmemdup(trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004752 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004753 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004754 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004755#if JOBS
4756 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004757 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004758 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004759 pid_t pgrp;
4760
4761 if (jp->nprocs == 0)
4762 pgrp = getpid();
4763 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004764 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004765 /* this can fail because we are doing it in the parent also */
4766 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004767 if (mode == FORK_FG)
4768 xtcsetpgrp(ttyfd, pgrp);
4769 setsignal(SIGTSTP);
4770 setsignal(SIGTTOU);
4771 } else
4772#endif
4773 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004774 /* man bash: "When job control is not in effect,
4775 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004776 ignoresig(SIGINT);
4777 ignoresig(SIGQUIT);
4778 if (jp->nprocs == 0) {
4779 close(0);
4780 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004781 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004782 }
4783 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004784 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004785 if (iflag) { /* why if iflag only? */
4786 setsignal(SIGINT);
4787 setsignal(SIGTERM);
4788 }
4789 /* man bash:
4790 * "In all cases, bash ignores SIGQUIT. Non-builtin
4791 * commands run by bash have signal handlers
4792 * set to the values inherited by the shell
4793 * from its parent".
4794 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004795 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004796 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004797#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004798 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004799 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004800 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004801 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004802 /* "jobs": we do not want to clear job list for it,
4803 * instead we remove only _its_ own_ job from job list.
4804 * This makes "jobs .... | cat" more useful.
4805 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004806 freejob(curjob);
4807 return;
4808 }
4809#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004810 for (jp = curjob; jp; jp = jp->prev_job)
4811 freejob(jp);
4812 jobless = 0;
4813}
4814
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004815/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004816#if !JOBS
4817#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4818#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004819static void
4820forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4821{
4822 TRACE(("In parent shell: child = %d\n", pid));
4823 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004824 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4825 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004826 jobless++;
4827 return;
4828 }
4829#if JOBS
4830 if (mode != FORK_NOJOB && jp->jobctl) {
4831 int pgrp;
4832
4833 if (jp->nprocs == 0)
4834 pgrp = pid;
4835 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004836 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004837 /* This can fail because we are doing it in the child also */
4838 setpgid(pid, pgrp);
4839 }
4840#endif
4841 if (mode == FORK_BG) {
4842 backgndpid = pid; /* set $! */
4843 set_curjob(jp, CUR_RUNNING);
4844 }
4845 if (jp) {
4846 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004847 ps->ps_pid = pid;
4848 ps->ps_status = -1;
4849 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004850#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004851 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004852 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004853#endif
4854 }
4855}
4856
4857static int
4858forkshell(struct job *jp, union node *n, int mode)
4859{
4860 int pid;
4861
4862 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4863 pid = fork();
4864 if (pid < 0) {
4865 TRACE(("Fork failed, errno=%d", errno));
4866 if (jp)
4867 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004868 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004869 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004870 if (pid == 0) {
4871 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004872 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004873 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004874 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004875 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004876 return pid;
4877}
4878
4879/*
4880 * Wait for job to finish.
4881 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004882 * Under job control we have the problem that while a child process
4883 * is running interrupts generated by the user are sent to the child
4884 * but not to the shell. This means that an infinite loop started by
4885 * an interactive user may be hard to kill. With job control turned off,
4886 * an interactive user may place an interactive program inside a loop.
4887 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004888 * these interrupts to also abort the loop. The approach we take here
4889 * is to have the shell ignore interrupt signals while waiting for a
4890 * foreground process to terminate, and then send itself an interrupt
4891 * signal if the child process was terminated by an interrupt signal.
4892 * Unfortunately, some programs want to do a bit of cleanup and then
4893 * exit on interrupt; unless these processes terminate themselves by
4894 * sending a signal to themselves (instead of calling exit) they will
4895 * confuse this approach.
4896 *
4897 * Called with interrupts off.
4898 */
4899static int
4900waitforjob(struct job *jp)
4901{
4902 int st;
4903
4904 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004905
4906 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004907 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004908 /* In non-interactive shells, we _can_ get
4909 * a keyboard signal here and be EINTRed,
4910 * but we just loop back, waiting for command to complete.
4911 *
4912 * man bash:
4913 * "If bash is waiting for a command to complete and receives
4914 * a signal for which a trap has been set, the trap
4915 * will not be executed until the command completes."
4916 *
4917 * Reality is that even if trap is not set, bash
4918 * will not act on the signal until command completes.
4919 * Try this. sleep5intoff.c:
4920 * #include <signal.h>
4921 * #include <unistd.h>
4922 * int main() {
4923 * sigset_t set;
4924 * sigemptyset(&set);
4925 * sigaddset(&set, SIGINT);
4926 * sigaddset(&set, SIGQUIT);
4927 * sigprocmask(SIG_BLOCK, &set, NULL);
4928 * sleep(5);
4929 * return 0;
4930 * }
4931 * $ bash -c './sleep5intoff; echo hi'
4932 * ^C^C^C^C <--- pressing ^C once a second
4933 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004934 * $ bash -c './sleep5intoff; echo hi'
4935 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4936 * $ _
4937 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004938 dowait(DOWAIT_BLOCK, jp);
4939 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004940 INT_ON;
4941
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004942 st = getstatus(jp);
4943#if JOBS
4944 if (jp->jobctl) {
4945 xtcsetpgrp(ttyfd, rootpid);
4946 /*
4947 * This is truly gross.
4948 * If we're doing job control, then we did a TIOCSPGRP which
4949 * caused us (the shell) to no longer be in the controlling
4950 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4951 * intuit from the subprocess exit status whether a SIGINT
4952 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4953 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004954 if (jp->sigint) /* TODO: do the same with all signals */
4955 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004956 }
4957 if (jp->state == JOBDONE)
4958#endif
4959 freejob(jp);
4960 return st;
4961}
4962
4963/*
4964 * return 1 if there are stopped jobs, otherwise 0
4965 */
4966static int
4967stoppedjobs(void)
4968{
4969 struct job *jp;
4970 int retval;
4971
4972 retval = 0;
4973 if (job_warning)
4974 goto out;
4975 jp = curjob;
4976 if (jp && jp->state == JOBSTOPPED) {
4977 out2str("You have stopped jobs.\n");
4978 job_warning = 2;
4979 retval++;
4980 }
4981 out:
4982 return retval;
4983}
4984
4985
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004986/* ============ redir.c
4987 *
4988 * Code for dealing with input/output redirection.
4989 */
4990
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01004991#undef EMPTY
4992#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004993#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00004994#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00004995
4996/*
4997 * Open a file in noclobber mode.
4998 * The code was copied from bash.
4999 */
5000static int
5001noclobberopen(const char *fname)
5002{
5003 int r, fd;
5004 struct stat finfo, finfo2;
5005
5006 /*
5007 * If the file exists and is a regular file, return an error
5008 * immediately.
5009 */
5010 r = stat(fname, &finfo);
5011 if (r == 0 && S_ISREG(finfo.st_mode)) {
5012 errno = EEXIST;
5013 return -1;
5014 }
5015
5016 /*
5017 * If the file was not present (r != 0), make sure we open it
5018 * exclusively so that if it is created before we open it, our open
5019 * will fail. Make sure that we do not truncate an existing file.
5020 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5021 * file was not a regular file, we leave O_EXCL off.
5022 */
5023 if (r != 0)
5024 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5025 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5026
5027 /* If the open failed, return the file descriptor right away. */
5028 if (fd < 0)
5029 return fd;
5030
5031 /*
5032 * OK, the open succeeded, but the file may have been changed from a
5033 * non-regular file to a regular file between the stat and the open.
5034 * We are assuming that the O_EXCL open handles the case where FILENAME
5035 * did not exist and is symlinked to an existing file between the stat
5036 * and open.
5037 */
5038
5039 /*
5040 * If we can open it and fstat the file descriptor, and neither check
5041 * revealed that it was a regular file, and the file has not been
5042 * replaced, return the file descriptor.
5043 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005044 if (fstat(fd, &finfo2) == 0
5045 && !S_ISREG(finfo2.st_mode)
5046 && finfo.st_dev == finfo2.st_dev
5047 && finfo.st_ino == finfo2.st_ino
5048 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005049 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005050 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005051
5052 /* The file has been replaced. badness. */
5053 close(fd);
5054 errno = EEXIST;
5055 return -1;
5056}
5057
5058/*
5059 * Handle here documents. Normally we fork off a process to write the
5060 * data to a pipe. If the document is short, we can stuff the data in
5061 * the pipe without forking.
5062 */
5063/* openhere needs this forward reference */
5064static void expandhere(union node *arg, int fd);
5065static int
5066openhere(union node *redir)
5067{
5068 int pip[2];
5069 size_t len = 0;
5070
5071 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005072 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005073 if (redir->type == NHERE) {
5074 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005075 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005076 full_write(pip[1], redir->nhere.doc->narg.text, len);
5077 goto out;
5078 }
5079 }
5080 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005081 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005082 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005083 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5084 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5085 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5086 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005087 signal(SIGPIPE, SIG_DFL);
5088 if (redir->type == NHERE)
5089 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005090 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005091 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005092 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005093 }
5094 out:
5095 close(pip[1]);
5096 return pip[0];
5097}
5098
5099static int
5100openredirect(union node *redir)
5101{
5102 char *fname;
5103 int f;
5104
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02005105 fname = redir->nfile.expfname;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005106 switch (redir->nfile.type) {
5107 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005108 f = open(fname, O_RDONLY);
5109 if (f < 0)
5110 goto eopen;
5111 break;
5112 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005113 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005114 if (f < 0)
5115 goto ecreate;
5116 break;
5117 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005118#if ENABLE_ASH_BASH_COMPAT
5119 case NTO2:
5120#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005121 /* Take care of noclobber mode. */
5122 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005123 f = noclobberopen(fname);
5124 if (f < 0)
5125 goto ecreate;
5126 break;
5127 }
5128 /* FALLTHROUGH */
5129 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005130 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5131 if (f < 0)
5132 goto ecreate;
5133 break;
5134 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005135 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5136 if (f < 0)
5137 goto ecreate;
5138 break;
5139 default:
5140#if DEBUG
5141 abort();
5142#endif
5143 /* Fall through to eliminate warning. */
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005144/* Our single caller does this itself */
Denis Vlasenko0b769642008-07-24 07:54:57 +00005145// case NTOFD:
5146// case NFROMFD:
5147// f = -1;
5148// break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005149 case NHERE:
5150 case NXHERE:
5151 f = openhere(redir);
5152 break;
5153 }
5154
5155 return f;
5156 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005157 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005158 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005159 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005160}
5161
5162/*
5163 * Copy a file descriptor to be >= to. Returns -1
5164 * if the source file descriptor is closed, EMPTY if there are no unused
5165 * file descriptors left.
5166 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005167/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5168 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005169enum {
5170 COPYFD_EXACT = (int)~(INT_MAX),
5171 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5172};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005173static int
5174copyfd(int from, int to)
5175{
5176 int newfd;
5177
Denis Vlasenko5a867312008-07-24 19:46:38 +00005178 if (to & COPYFD_EXACT) {
5179 to &= ~COPYFD_EXACT;
5180 /*if (from != to)*/
5181 newfd = dup2(from, to);
5182 } else {
5183 newfd = fcntl(from, F_DUPFD, to);
5184 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005185 if (newfd < 0) {
5186 if (errno == EMFILE)
5187 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005188 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005189 ash_msg_and_raise_error("%d: %m", from);
5190 }
5191 return newfd;
5192}
5193
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005194/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005195struct two_fd_t {
5196 int orig, copy;
5197};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005198struct redirtab {
5199 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005200 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005201 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005202 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005203};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005204#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005205
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005206static int need_to_remember(struct redirtab *rp, int fd)
5207{
5208 int i;
5209
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005210 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005211 return 0;
5212
5213 for (i = 0; i < rp->pair_count; i++) {
5214 if (rp->two_fd[i].orig == fd) {
5215 /* already remembered */
5216 return 0;
5217 }
5218 }
5219 return 1;
5220}
5221
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005222/* "hidden" fd is a fd used to read scripts, or a copy of such */
5223static int is_hidden_fd(struct redirtab *rp, int fd)
5224{
5225 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005226 struct parsefile *pf;
5227
5228 if (fd == -1)
5229 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005230 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005231 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005232 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005233 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005234 * $ ash # running ash interactively
5235 * $ . ./script.sh
5236 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005237 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005238 * it's still ok to use it: "read" builtin uses it,
5239 * why should we cripple "exec" builtin?
5240 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005241 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005242 return 1;
5243 }
5244 pf = pf->prev;
5245 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005246
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005247 if (!rp)
5248 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005249 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005250 fd |= COPYFD_RESTORE;
5251 for (i = 0; i < rp->pair_count; i++) {
5252 if (rp->two_fd[i].copy == fd) {
5253 return 1;
5254 }
5255 }
5256 return 0;
5257}
5258
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005259/*
5260 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5261 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005262 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005263 */
5264/* flags passed to redirect */
5265#define REDIR_PUSH 01 /* save previous values of file descriptors */
5266#define REDIR_SAVEFD2 03 /* set preverrout */
5267static void
5268redirect(union node *redir, int flags)
5269{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005270 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005271 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005272 int i;
5273 int fd;
5274 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005275 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005276
Denis Vlasenko01631112007-12-16 17:20:38 +00005277 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005278 if (!redir) {
5279 return;
5280 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005281
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005282 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005283 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005284 INT_OFF;
5285 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005286 union node *tmp = redir;
5287 do {
5288 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005289#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005290 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005291 sv_pos++;
5292#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005293 tmp = tmp->nfile.next;
5294 } while (tmp);
5295 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005296 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005297 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005298 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005299 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005300 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005301 while (sv_pos > 0) {
5302 sv_pos--;
5303 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5304 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005305 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005306
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005307 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005308 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005309 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005310 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005311 right_fd = redir->ndup.dupfd;
5312 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005313 /* redirect from/to same file descriptor? */
5314 if (right_fd == fd)
5315 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005316 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005317 if (is_hidden_fd(sv, right_fd)) {
5318 errno = EBADF; /* as if it is closed */
5319 ash_msg_and_raise_error("%d: %m", right_fd);
5320 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005321 newfd = -1;
5322 } else {
5323 newfd = openredirect(redir); /* always >= 0 */
5324 if (fd == newfd) {
5325 /* Descriptor wasn't open before redirect.
5326 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005327 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005328 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005329 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005330 continue;
5331 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005332 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005333#if ENABLE_ASH_BASH_COMPAT
5334 redirect_more:
5335#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005336 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005337 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005338 /* Careful to not accidentally "save"
5339 * to the same fd as right side fd in N>&M */
5340 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5341 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005342/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5343 * are closed in popredir() in the child, preventing them from leaking
5344 * into child. (popredir() also cleans up the mess in case of failures)
5345 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005346 if (i == -1) {
5347 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005348 if (i != EBADF) {
5349 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005350 if (newfd >= 0)
5351 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005352 errno = i;
5353 ash_msg_and_raise_error("%d: %m", fd);
5354 /* NOTREACHED */
5355 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005356 /* EBADF: it is not open - good, remember to close it */
5357 remember_to_close:
5358 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005359 } else { /* fd is open, save its copy */
5360 /* "exec fd>&-" should not close fds
5361 * which point to script file(s).
5362 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005363 if (is_hidden_fd(sv, fd))
5364 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005365 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005366 if (fd == 2)
5367 copied_fd2 = i;
5368 sv->two_fd[sv_pos].orig = fd;
5369 sv->two_fd[sv_pos].copy = i;
5370 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005371 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005372 if (newfd < 0) {
5373 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005374 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005375 /* Don't want to trigger debugging */
5376 if (fd != -1)
5377 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005378 } else {
5379 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005380 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005381 } else if (fd != newfd) { /* move newfd to fd */
5382 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005383#if ENABLE_ASH_BASH_COMPAT
5384 if (!(redir->nfile.type == NTO2 && fd == 2))
5385#endif
5386 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005387 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005388#if ENABLE_ASH_BASH_COMPAT
5389 if (redir->nfile.type == NTO2 && fd == 1) {
5390 /* We already redirected it to fd 1, now copy it to 2 */
5391 newfd = 1;
5392 fd = 2;
5393 goto redirect_more;
5394 }
5395#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005396 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005397
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005398 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005399 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5400 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005401}
5402
5403/*
5404 * Undo the effects of the last redirection.
5405 */
5406static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005407popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005408{
5409 struct redirtab *rp;
5410 int i;
5411
Denis Vlasenko01631112007-12-16 17:20:38 +00005412 if (--g_nullredirs >= 0)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005413 return;
5414 INT_OFF;
5415 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005416 for (i = 0; i < rp->pair_count; i++) {
5417 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005418 int copy = rp->two_fd[i].copy;
5419 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005420 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005421 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005422 continue;
5423 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005424 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005425 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005426 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005427 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005428 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005429 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005430 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005431 }
5432 }
5433 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005434 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005435 free(rp);
5436 INT_ON;
5437}
5438
5439/*
5440 * Undo all redirections. Called on error or interrupt.
5441 */
5442
5443/*
5444 * Discard all saved file descriptors.
5445 */
5446static void
5447clearredir(int drop)
5448{
5449 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005450 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005451 if (!redirlist)
5452 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005453 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005454 }
5455}
5456
5457static int
5458redirectsafe(union node *redir, int flags)
5459{
5460 int err;
5461 volatile int saveint;
5462 struct jmploc *volatile savehandler = exception_handler;
5463 struct jmploc jmploc;
5464
5465 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005466 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5467 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005468 if (!err) {
5469 exception_handler = &jmploc;
5470 redirect(redir, flags);
5471 }
5472 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005473 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005474 longjmp(exception_handler->loc, 1);
5475 RESTORE_INT(saveint);
5476 return err;
5477}
5478
5479
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005480/* ============ Routines to expand arguments to commands
5481 *
5482 * We have to deal with backquotes, shell variables, and file metacharacters.
5483 */
5484
Mike Frysinger98c52642009-04-02 10:02:37 +00005485#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005486static arith_t
5487ash_arith(const char *s)
5488{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005489 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005490 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005491
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005492 math_state.lookupvar = lookupvar;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02005493 math_state.setvar = setvar0;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005494 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005495
5496 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005497 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005498 if (math_state.errmsg)
5499 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005500 INT_ON;
5501
5502 return result;
5503}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005504#endif
5505
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005506/*
5507 * expandarg flags
5508 */
5509#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5510#define EXP_TILDE 0x2 /* do normal tilde expansion */
5511#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5512#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5513#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
Ron Yorston549deab2015-05-18 09:57:51 +02005514#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005515#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5516#define EXP_WORD 0x80 /* expand word in parameter expansion */
Ron Yorston3df47f92015-05-18 09:53:26 +02005517#define EXP_QUOTED 0x100 /* expand word in double quotes */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005518/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005519 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005520 */
5521#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5522#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005523#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5524#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
Ron Yorston417622c2015-05-18 09:59:14 +02005525#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005526
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005527/* Add CTLESC when necessary. */
Ron Yorston549deab2015-05-18 09:57:51 +02005528#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR)
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005529/* Do not skip NUL characters. */
5530#define QUOTES_KEEPNUL EXP_TILDE
5531
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005532/*
5533 * Structure specifying which parts of the string should be searched
5534 * for IFS characters.
5535 */
5536struct ifsregion {
5537 struct ifsregion *next; /* next region in list */
5538 int begoff; /* offset of start of region */
5539 int endoff; /* offset of end of region */
5540 int nulonly; /* search for nul bytes only */
5541};
5542
5543struct arglist {
5544 struct strlist *list;
5545 struct strlist **lastp;
5546};
5547
5548/* output of current string */
5549static char *expdest;
5550/* list of back quote expressions */
5551static struct nodelist *argbackq;
5552/* first struct in list of ifs regions */
5553static struct ifsregion ifsfirst;
5554/* last struct in list */
5555static struct ifsregion *ifslastp;
5556/* holds expanded arg list */
5557static struct arglist exparg;
5558
5559/*
5560 * Our own itoa().
5561 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005562#if !ENABLE_SH_MATH_SUPPORT
5563/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5564typedef long arith_t;
5565# define ARITH_FMT "%ld"
5566#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005567static int
5568cvtnum(arith_t num)
5569{
5570 int len;
5571
Denys Vlasenko9c541002015-10-07 15:44:36 +02005572 expdest = makestrspace(sizeof(arith_t)*3 + 2, expdest);
5573 len = fmtstr(expdest, sizeof(arith_t)*3 + 2, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005574 STADJUST(len, expdest);
5575 return len;
5576}
5577
5578static size_t
5579esclen(const char *start, const char *p)
5580{
5581 size_t esc = 0;
5582
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005583 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005584 esc++;
5585 }
5586 return esc;
5587}
5588
5589/*
5590 * Remove any CTLESC characters from a string.
5591 */
5592static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005593rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005594{
Ron Yorston417622c2015-05-18 09:59:14 +02005595 static const char qchars[] ALIGN1 = {
5596 IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005597
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005598 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005599 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005600 unsigned protect_against_glob;
5601 unsigned globbing;
Ron Yorston417622c2015-05-18 09:59:14 +02005602 IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005603
Ron Yorston417622c2015-05-18 09:59:14 +02005604 p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005605 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005606 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005607
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005608 q = p;
5609 r = str;
5610 if (flag & RMESCAPE_ALLOC) {
5611 size_t len = p - str;
5612 size_t fulllen = len + strlen(p) + 1;
5613
5614 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005615 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005616 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005617 /* p and str may be invalidated by makestrspace */
5618 str = (char *)stackblock() + strloc;
5619 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005620 } else if (flag & RMESCAPE_HEAP) {
5621 r = ckmalloc(fulllen);
5622 } else {
5623 r = stalloc(fulllen);
5624 }
5625 q = r;
5626 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005627 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005628 }
5629 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005630
Ron Yorston549deab2015-05-18 09:57:51 +02005631 inquotes = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005632 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005633 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005634 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005635 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005636// Note: both inquotes and protect_against_glob only affect whether
5637// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005638 inquotes = ~inquotes;
5639 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005640 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005641 continue;
5642 }
Ron Yorston549deab2015-05-18 09:57:51 +02005643 if ((unsigned char)*p == CTLESC) {
5644 p++;
5645 if (protect_against_glob) {
5646 *q++ = '\\';
5647 }
5648 } else if (*p == '\\' && !inquotes) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005649 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005650 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005651 goto copy;
5652 }
Ron Yorston417622c2015-05-18 09:59:14 +02005653#if ENABLE_ASH_BASH_COMPAT
5654 else if (*p == '/' && slash) {
5655 /* stop handling globbing and mark location of slash */
5656 globbing = slash = 0;
5657 *p = CTLESC;
5658 }
5659#endif
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005660 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005661 copy:
5662 *q++ = *p++;
5663 }
5664 *q = '\0';
5665 if (flag & RMESCAPE_GROW) {
5666 expdest = r;
5667 STADJUST(q - r + 1, expdest);
5668 }
5669 return r;
5670}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005671#define pmatch(a, b) !fnmatch((a), (b), 0)
5672
5673/*
5674 * Prepare a pattern for a expmeta (internal glob(3)) call.
5675 *
5676 * Returns an stalloced string.
5677 */
5678static char *
Ron Yorston549deab2015-05-18 09:57:51 +02005679preglob(const char *pattern, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005680{
Ron Yorston549deab2015-05-18 09:57:51 +02005681 return rmescapes((char *)pattern, flag | RMESCAPE_GLOB);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005682}
5683
5684/*
5685 * Put a string on the stack.
5686 */
5687static void
5688memtodest(const char *p, size_t len, int syntax, int quotes)
5689{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005690 char *q;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005691
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005692 if (!len)
5693 return;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005694
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005695 q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest);
5696
5697 do {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005698 unsigned char c = *p++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005699 if (c) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005700 int n = SIT(c, syntax);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005701 if ((quotes & QUOTES_ESC) &&
Ron Yorston549deab2015-05-18 09:57:51 +02005702 ((n == CCTL) ||
5703 (((quotes & EXP_FULL) || syntax != BASESYNTAX) &&
5704 n == CBACK)))
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005705 USTPUTC(CTLESC, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005706 } else if (!(quotes & QUOTES_KEEPNUL))
5707 continue;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005708 USTPUTC(c, q);
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005709 } while (--len);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005710
5711 expdest = q;
5712}
5713
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005714static size_t
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005715strtodest(const char *p, int syntax, int quotes)
5716{
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005717 size_t len = strlen(p);
5718 memtodest(p, len, syntax, quotes);
5719 return len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005720}
5721
5722/*
5723 * Record the fact that we have to scan this region of the
5724 * string for IFS characters.
5725 */
5726static void
5727recordregion(int start, int end, int nulonly)
5728{
5729 struct ifsregion *ifsp;
5730
5731 if (ifslastp == NULL) {
5732 ifsp = &ifsfirst;
5733 } else {
5734 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005735 ifsp = ckzalloc(sizeof(*ifsp));
5736 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005737 ifslastp->next = ifsp;
5738 INT_ON;
5739 }
5740 ifslastp = ifsp;
5741 ifslastp->begoff = start;
5742 ifslastp->endoff = end;
5743 ifslastp->nulonly = nulonly;
5744}
5745
5746static void
5747removerecordregions(int endoff)
5748{
5749 if (ifslastp == NULL)
5750 return;
5751
5752 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005753 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005754 struct ifsregion *ifsp;
5755 INT_OFF;
5756 ifsp = ifsfirst.next->next;
5757 free(ifsfirst.next);
5758 ifsfirst.next = ifsp;
5759 INT_ON;
5760 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005761 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005762 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005763 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005764 ifslastp = &ifsfirst;
5765 ifsfirst.endoff = endoff;
5766 }
5767 return;
5768 }
5769
5770 ifslastp = &ifsfirst;
5771 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005772 ifslastp = ifslastp->next;
5773 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005774 struct ifsregion *ifsp;
5775 INT_OFF;
5776 ifsp = ifslastp->next->next;
5777 free(ifslastp->next);
5778 ifslastp->next = ifsp;
5779 INT_ON;
5780 }
5781 if (ifslastp->endoff > endoff)
5782 ifslastp->endoff = endoff;
5783}
5784
5785static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005786exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005787{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005788 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005789 char *name;
5790 struct passwd *pw;
5791 const char *home;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02005792 int quotes = flags & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005793
5794 name = p + 1;
5795
5796 while ((c = *++p) != '\0') {
5797 switch (c) {
5798 case CTLESC:
5799 return startp;
5800 case CTLQUOTEMARK:
5801 return startp;
5802 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005803 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005804 goto done;
5805 break;
5806 case '/':
5807 case CTLENDVAR:
5808 goto done;
5809 }
5810 }
5811 done:
5812 *p = '\0';
5813 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005814 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005815 } else {
5816 pw = getpwnam(name);
5817 if (pw == NULL)
5818 goto lose;
5819 home = pw->pw_dir;
5820 }
5821 if (!home || !*home)
5822 goto lose;
5823 *p = c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005824 strtodest(home, SQSYNTAX, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005825 return p;
5826 lose:
5827 *p = c;
5828 return startp;
5829}
5830
5831/*
5832 * Execute a command inside back quotes. If it's a builtin command, we
5833 * want to save its output in a block obtained from malloc. Otherwise
5834 * we fork off a subprocess and get the output of the command via a pipe.
5835 * Should be called with interrupts off.
5836 */
5837struct backcmd { /* result of evalbackcmd */
5838 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005839 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005840 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005841 struct job *jp; /* job structure for command */
5842};
5843
5844/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005845static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005846#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02005847static void evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005848
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005849static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005850evalbackcmd(union node *n, struct backcmd *result)
5851{
5852 int saveherefd;
5853
5854 result->fd = -1;
5855 result->buf = NULL;
5856 result->nleft = 0;
5857 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005858 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005859 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005860
5861 saveherefd = herefd;
5862 herefd = -1;
5863
5864 {
5865 int pip[2];
5866 struct job *jp;
5867
5868 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005869 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005870 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005871 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5872 FORCE_INT_ON;
5873 close(pip[0]);
5874 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005875 /*close(1);*/
5876 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005877 close(pip[1]);
5878 }
5879 eflag = 0;
5880 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5881 /* NOTREACHED */
5882 }
5883 close(pip[1]);
5884 result->fd = pip[0];
5885 result->jp = jp;
5886 }
5887 herefd = saveherefd;
5888 out:
5889 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5890 result->fd, result->buf, result->nleft, result->jp));
5891}
5892
5893/*
5894 * Expand stuff in backwards quotes.
5895 */
5896static void
Ron Yorston549deab2015-05-18 09:57:51 +02005897expbackq(union node *cmd, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005898{
5899 struct backcmd in;
5900 int i;
5901 char buf[128];
5902 char *p;
5903 char *dest;
5904 int startloc;
Ron Yorston549deab2015-05-18 09:57:51 +02005905 int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005906 struct stackmark smark;
5907
5908 INT_OFF;
5909 setstackmark(&smark);
5910 dest = expdest;
5911 startloc = dest - (char *)stackblock();
5912 grabstackstr(dest);
5913 evalbackcmd(cmd, &in);
5914 popstackmark(&smark);
5915
5916 p = in.buf;
5917 i = in.nleft;
5918 if (i == 0)
5919 goto read;
5920 for (;;) {
Ron Yorston549deab2015-05-18 09:57:51 +02005921 memtodest(p, i, syntax, flag & QUOTES_ESC);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005922 read:
5923 if (in.fd < 0)
5924 break;
Ron Yorston61d6ae22015-04-19 10:50:25 +01005925 i = nonblock_immune_read(in.fd, buf, sizeof(buf));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005926 TRACE(("expbackq: read returns %d\n", i));
5927 if (i <= 0)
5928 break;
5929 p = buf;
5930 }
5931
Denis Vlasenko60818682007-09-28 22:07:23 +00005932 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005933 if (in.fd >= 0) {
5934 close(in.fd);
5935 back_exitstatus = waitforjob(in.jp);
5936 }
5937 INT_ON;
5938
5939 /* Eat all trailing newlines */
5940 dest = expdest;
5941 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5942 STUNPUTC(dest);
5943 expdest = dest;
5944
Ron Yorston549deab2015-05-18 09:57:51 +02005945 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005946 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005947 TRACE(("evalbackq: size:%d:'%.*s'\n",
5948 (int)((dest - (char *)stackblock()) - startloc),
5949 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005950 stackblock() + startloc));
5951}
5952
Mike Frysinger98c52642009-04-02 10:02:37 +00005953#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005954/*
5955 * Expand arithmetic expression. Backup to start of expression,
5956 * evaluate, place result in (backed up) result, adjust string position.
5957 */
5958static void
Ron Yorston549deab2015-05-18 09:57:51 +02005959expari(int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005960{
5961 char *p, *start;
5962 int begoff;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005963 int len;
5964
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005965 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005966
5967 /*
5968 * This routine is slightly over-complicated for
5969 * efficiency. Next we scan backwards looking for the
5970 * start of arithmetic.
5971 */
5972 start = stackblock();
5973 p = expdest - 1;
5974 *p = '\0';
5975 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005976 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005977 int esc;
5978
Denys Vlasenkocd716832009-11-28 22:14:02 +01005979 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005980 p--;
5981#if DEBUG
5982 if (p < start) {
5983 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5984 }
5985#endif
5986 }
5987
5988 esc = esclen(start, p);
5989 if (!(esc % 2)) {
5990 break;
5991 }
5992
5993 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005994 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005995
5996 begoff = p - start;
5997
5998 removerecordregions(begoff);
5999
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000 expdest = p;
6001
Ron Yorston549deab2015-05-18 09:57:51 +02006002 if (flag & QUOTES_ESC)
6003 rmescapes(p + 1, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006004
Ron Yorston549deab2015-05-18 09:57:51 +02006005 len = cvtnum(ash_arith(p + 1));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006006
Ron Yorston549deab2015-05-18 09:57:51 +02006007 if (!(flag & EXP_QUOTED))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006008 recordregion(begoff, begoff + len, 0);
6009}
6010#endif
6011
6012/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006013static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006014
6015/*
6016 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6017 * characters to allow for further processing. Otherwise treat
6018 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006019 *
6020 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6021 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6022 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006023 */
6024static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006025argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006026{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006027 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006028 '=',
6029 ':',
6030 CTLQUOTEMARK,
6031 CTLENDVAR,
6032 CTLESC,
6033 CTLVAR,
6034 CTLBACKQ,
Mike Frysinger98c52642009-04-02 10:02:37 +00006035#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006036 CTLENDARI,
6037#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006038 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006039 };
6040 const char *reject = spclchars;
Ron Yorston3df47f92015-05-18 09:53:26 +02006041 int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006042 int inquotes;
6043 size_t length;
6044 int startloc;
6045
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006046 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006047 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006048 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006049 reject++;
6050 }
6051 inquotes = 0;
6052 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006053 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006054 char *q;
6055
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006056 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006057 tilde:
6058 q = p;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006059 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006060 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006061 }
6062 start:
6063 startloc = expdest - (char *)stackblock();
6064 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006065 unsigned char c;
6066
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006067 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006068 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006069 if (c) {
6070 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006071 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006072 ) {
6073 /* c == '=' || c == ':' || c == CTLENDARI */
6074 length++;
6075 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006076 }
6077 if (length > 0) {
6078 int newloc;
6079 expdest = stack_nputstr(p, length, expdest);
6080 newloc = expdest - (char *)stackblock();
6081 if (breakall && !inquotes && newloc > startloc) {
6082 recordregion(startloc, newloc, 0);
6083 }
6084 startloc = newloc;
6085 }
6086 p += length + 1;
6087 length = 0;
6088
6089 switch (c) {
6090 case '\0':
6091 goto breakloop;
6092 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006093 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006094 p--;
6095 continue;
6096 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006097 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006098 reject++;
6099 /* fall through */
6100 case ':':
6101 /*
6102 * sort of a hack - expand tildes in variable
6103 * assignments (after the first '=' and after ':'s).
6104 */
6105 if (*--p == '~') {
6106 goto tilde;
6107 }
6108 continue;
6109 }
6110
6111 switch (c) {
6112 case CTLENDVAR: /* ??? */
6113 goto breakloop;
6114 case CTLQUOTEMARK:
Ron Yorston549deab2015-05-18 09:57:51 +02006115 inquotes ^= EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006116 /* "$@" syntax adherence hack */
Ron Yorston549deab2015-05-18 09:57:51 +02006117 if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) {
6118 p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006119 goto start;
6120 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006121 addquote:
Ron Yorston549deab2015-05-18 09:57:51 +02006122 if (flags & QUOTES_ESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006123 p--;
6124 length++;
6125 startloc++;
6126 }
6127 break;
6128 case CTLESC:
6129 startloc++;
6130 length++;
Ron Yorston549deab2015-05-18 09:57:51 +02006131
6132 /*
6133 * Quoted parameter expansion pattern: remove quote
6134 * unless inside inner quotes or we have a literal
6135 * backslash.
6136 */
6137 if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
6138 EXP_QPAT && *p != '\\')
6139 break;
6140
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006141 goto addquote;
6142 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006143 TRACE(("argstr: evalvar('%s')\n", p));
Ron Yorston549deab2015-05-18 09:57:51 +02006144 p = evalvar(p, flags | inquotes, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006145 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006146 goto start;
6147 case CTLBACKQ:
Ron Yorston549deab2015-05-18 09:57:51 +02006148 expbackq(argbackq->n, flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006149 argbackq = argbackq->next;
6150 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006151#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006152 case CTLENDARI:
6153 p--;
Ron Yorston549deab2015-05-18 09:57:51 +02006154 expari(flags | inquotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006155 goto start;
6156#endif
6157 }
6158 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006159 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006160}
6161
6162static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006163scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6164 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006165{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006166 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006167 char c;
6168
6169 loc = startp;
6170 loc2 = rmesc;
6171 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006172 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006173 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006174
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006175 c = *loc2;
6176 if (zero) {
6177 *loc2 = '\0';
6178 s = rmesc;
6179 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006180 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006181
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006182 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006183 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006184 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006185 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006186 loc++;
6187 loc++;
6188 loc2++;
6189 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006190 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006191}
6192
6193static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006194scanright(char *startp, char *rmesc, char *rmescend,
6195 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006196{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006197#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6198 int try2optimize = match_at_start;
6199#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006200 int esc = 0;
6201 char *loc;
6202 char *loc2;
6203
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006204 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6205 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6206 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6207 * Logic:
6208 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6209 * and on each iteration they go back two/one char until they reach the beginning.
6210 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6211 */
6212 /* TODO: document in what other circumstances we are called. */
6213
6214 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006215 int match;
6216 char c = *loc2;
6217 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006218 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006219 *loc2 = '\0';
6220 s = rmesc;
6221 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006222 match = pmatch(pattern, s);
6223 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006224 *loc2 = c;
6225 if (match)
6226 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006227#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6228 if (try2optimize) {
6229 /* Maybe we can optimize this:
6230 * if pattern ends with unescaped *, we can avoid checking
6231 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6232 * it wont match truncated "raw_value_of_" strings too.
6233 */
6234 unsigned plen = strlen(pattern);
6235 /* Does it end with "*"? */
6236 if (plen != 0 && pattern[--plen] == '*') {
6237 /* "xxxx*" is not escaped */
6238 /* "xxx\*" is escaped */
6239 /* "xx\\*" is not escaped */
6240 /* "x\\\*" is escaped */
6241 int slashes = 0;
6242 while (plen != 0 && pattern[--plen] == '\\')
6243 slashes++;
6244 if (!(slashes & 1))
6245 break; /* ends with unescaped "*" */
6246 }
6247 try2optimize = 0;
6248 }
6249#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006250 loc--;
6251 if (quotes) {
6252 if (--esc < 0) {
6253 esc = esclen(startp, loc);
6254 }
6255 if (esc % 2) {
6256 esc--;
6257 loc--;
6258 }
6259 }
6260 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006261 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006262}
6263
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006264static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006265static void
6266varunset(const char *end, const char *var, const char *umsg, int varflags)
6267{
6268 const char *msg;
6269 const char *tail;
6270
6271 tail = nullstr;
6272 msg = "parameter not set";
6273 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006274 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006275 if (varflags & VSNUL)
6276 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006277 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006278 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006279 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006280 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006281 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006282}
6283
6284static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006285subevalvar(char *p, char *varname, int strloc, int subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006286 int startloc, int varflags, int flag, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006287{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006288 struct nodelist *saveargbackq = argbackq;
Ron Yorston549deab2015-05-18 09:57:51 +02006289 int quotes = flag & QUOTES_ESC;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006290 char *startp;
6291 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006292 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006293 char *str;
Ron Yorston417622c2015-05-18 09:59:14 +02006294 IF_ASH_BASH_COMPAT(char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006295 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006296 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006297 int amount, resetloc;
6298 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006299 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006300 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006301
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006302 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6303 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006304
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006305 herefd = -1;
Ron Yorstoneb6b48b2015-05-18 09:51:35 +02006306 argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
Ron Yorston549deab2015-05-18 09:57:51 +02006307 (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0),
6308 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006309 STPUTC('\0', expdest);
6310 herefd = saveherefd;
6311 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006312 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006313
6314 switch (subtype) {
6315 case VSASSIGN:
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02006316 setvar0(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006317 amount = startp - expdest;
6318 STADJUST(amount, expdest);
6319 return startp;
6320
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006321 case VSQUESTION:
6322 varunset(p, varname, startp, varflags);
6323 /* NOTREACHED */
6324
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006325#if ENABLE_ASH_BASH_COMPAT
6326 case VSSUBSTR:
6327 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006328 /* Read POS in ${var:POS:LEN} */
6329 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006330 len = str - startp - 1;
6331
6332 /* *loc != '\0', guaranteed by parser */
6333 if (quotes) {
6334 char *ptr;
6335
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006336 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006337 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006338 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006339 len--;
6340 ptr++;
6341 }
6342 }
6343 }
6344 orig_len = len;
6345
6346 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006347 /* ${var::LEN} */
6348 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006349 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006350 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006351 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006352 while (*loc && *loc != ':') {
6353 /* TODO?
6354 * bash complains on: var=qwe; echo ${var:1a:123}
6355 if (!isdigit(*loc))
6356 ash_msg_and_raise_error(msg_illnum, str);
6357 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006358 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006359 }
6360 if (*loc++ == ':') {
6361 len = number(loc);
6362 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006363 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006364 if (pos < 0) {
6365 /* ${VAR:$((-n)):l} starts n chars from the end */
6366 pos = orig_len + pos;
6367 }
6368 if ((unsigned)pos >= orig_len) {
6369 /* apart from obvious ${VAR:999999:l},
6370 * covers ${VAR:$((-9999999)):l} - result is ""
6371 * (bash-compat)
6372 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006373 pos = 0;
6374 len = 0;
6375 }
6376 if (len > (orig_len - pos))
6377 len = orig_len - pos;
6378
6379 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006380 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006381 str++;
6382 }
6383 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006384 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006385 *loc++ = *str++;
6386 *loc++ = *str++;
6387 }
6388 *loc = '\0';
6389 amount = loc - expdest;
6390 STADJUST(amount, expdest);
6391 return loc;
6392#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006393 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006394
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006395 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006396
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006397 /* We'll comeback here if we grow the stack while handling
6398 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6399 * stack will need rebasing, and we'll need to remove our work
6400 * areas each time
6401 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006402 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006403
6404 amount = expdest - ((char *)stackblock() + resetloc);
6405 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006406 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006407
6408 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006409 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006410 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006411 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006412 if (rmesc != startp) {
6413 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006414 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006415 }
6416 }
6417 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006418 str = (char *)stackblock() + strloc;
Ron Yorston417622c2015-05-18 09:59:14 +02006419 /*
6420 * Example: v='a\bc'; echo ${v/\\b/_\\_\z_}
6421 * The result is a_\_z_c (not a\_\_z_c)!
6422 *
6423 * The search pattern and replace string treat backslashes differently!
6424 * RMESCAPE_SLASH causes preglob to work differently on the pattern
6425 * and string. It's only used on the first call.
6426 */
6427 preglob(str, IF_ASH_BASH_COMPAT(
6428 (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ?
6429 RMESCAPE_SLASH :) 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006430
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006431#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006432 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006433 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006434 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006435
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006436 if (!repl) {
Ron Yorston417622c2015-05-18 09:59:14 +02006437 if ((repl=strchr(str, CTLESC)))
6438 *repl++ = '\0';
6439 else
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006440 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006441 }
Ron Yorston417622c2015-05-18 09:59:14 +02006442 //bb_error_msg("str:'%s' repl:'%s'", str, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006443
6444 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006445 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006446 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006447
6448 len = 0;
6449 idx = startp;
6450 end = str - 1;
6451 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006452 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006453 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006454 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006455 if (!loc) {
6456 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006457 char *restart_detect = stackblock();
6458 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006459 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006460 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006461 idx++;
6462 len++;
6463 STPUTC(*idx, expdest);
6464 }
6465 if (stackblock() != restart_detect)
6466 goto restart;
6467 idx++;
6468 len++;
6469 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006470 /* continue; - prone to quadratic behavior, smarter code: */
6471 if (idx >= end)
6472 break;
6473 if (str[0] == '*') {
6474 /* Pattern is "*foo". If "*foo" does not match "long_string",
6475 * it would never match "ong_string" etc, no point in trying.
6476 */
6477 goto skip_matching;
6478 }
6479 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006480 }
6481
6482 if (subtype == VSREPLACEALL) {
6483 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006484 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006485 idx++;
6486 idx++;
6487 rmesc++;
6488 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006489 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006490 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006491 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006492
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006493 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006494 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006495 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006496 if (quotes && *loc == '\\') {
6497 STPUTC(CTLESC, expdest);
6498 len++;
6499 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006500 STPUTC(*loc, expdest);
6501 if (stackblock() != restart_detect)
6502 goto restart;
6503 len++;
6504 }
6505
6506 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006507 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006508 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006509 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006510 STPUTC(*idx, expdest);
6511 if (stackblock() != restart_detect)
6512 goto restart;
6513 len++;
6514 idx++;
6515 }
6516 break;
6517 }
6518 }
6519
6520 /* We've put the replaced text into a buffer at workloc, now
6521 * move it to the right place and adjust the stack.
6522 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006523 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006524 startp = (char *)stackblock() + startloc;
6525 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006526 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006527 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006528 STADJUST(-amount, expdest);
6529 return startp;
6530 }
6531#endif /* ENABLE_ASH_BASH_COMPAT */
6532
6533 subtype -= VSTRIMRIGHT;
6534#if DEBUG
6535 if (subtype < 0 || subtype > 7)
6536 abort();
6537#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006538 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006539 zero = subtype >> 1;
6540 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6541 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6542
6543 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6544 if (loc) {
6545 if (zero) {
6546 memmove(startp, loc, str - loc);
6547 loc = startp + (str - loc) - 1;
6548 }
6549 *loc = '\0';
6550 amount = loc - expdest;
6551 STADJUST(amount, expdest);
6552 }
6553 return loc;
6554}
6555
6556/*
6557 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006558 * name parameter (examples):
6559 * ash -c 'echo $1' name:'1='
6560 * ash -c 'echo $qwe' name:'qwe='
6561 * ash -c 'echo $$' name:'$='
6562 * ash -c 'echo ${$}' name:'$='
6563 * ash -c 'echo ${$##q}' name:'$=q'
6564 * ash -c 'echo ${#$}' name:'$='
6565 * note: examples with bad shell syntax:
6566 * ash -c 'echo ${#$1}' name:'$=1'
6567 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006568 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006569static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006570varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006571{
Mike Frysinger98c52642009-04-02 10:02:37 +00006572 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006573 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006574 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006575 ssize_t len = 0;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006576 int sep;
Ron Yorston549deab2015-05-18 09:57:51 +02006577 int quoted = flags & EXP_QUOTED;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006578 int subtype = varflags & VSTYPE;
6579 int discard = subtype == VSPLUS || subtype == VSLENGTH;
6580 int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006581 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006582
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006583 sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0;
6584
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006585 switch (*name) {
6586 case '$':
6587 num = rootpid;
6588 goto numvar;
6589 case '?':
6590 num = exitstatus;
6591 goto numvar;
6592 case '#':
6593 num = shellparam.nparam;
6594 goto numvar;
6595 case '!':
6596 num = backgndpid;
6597 if (num == 0)
6598 return -1;
6599 numvar:
6600 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006601 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006602 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006603 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006604 for (i = NOPTS - 1; i >= 0; i--) {
6605 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006606 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607 len++;
6608 }
6609 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006610 check_1char_name:
6611#if 0
6612 /* handles cases similar to ${#$1} */
6613 if (name[2] != '\0')
6614 raise_error_syntax("bad substitution");
6615#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006616 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006617 case '@': {
6618 char **ap;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006619 char sepc;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006620
6621 if (quoted && (flags & EXP_FULL)) {
6622 /* note: this is not meant as PEOF value */
6623 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006624 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006625 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006626 /* fall through */
6627 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006628 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006629 param:
6630 ap = shellparam.p;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006631 sepc = sep;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006632 if (!ap)
6633 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006634 while ((p = *ap++) != NULL) {
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006635 len += strtodest(p, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006636
6637 if (*ap && sep) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006638 len++;
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006639 memtodest(&sepc, 1, syntax, quotes);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006640 }
6641 }
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006642 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006643 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006644 case '0':
6645 case '1':
6646 case '2':
6647 case '3':
6648 case '4':
6649 case '5':
6650 case '6':
6651 case '7':
6652 case '8':
6653 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006654 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006655 if (num < 0 || num > shellparam.nparam)
6656 return -1;
6657 p = num ? shellparam.p[num - 1] : arg0;
6658 goto value;
6659 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006660 /* NB: name has form "VAR=..." */
6661
6662 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6663 * which should be considered before we check variables. */
6664 if (var_str_list) {
6665 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6666 p = NULL;
6667 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006668 char *str, *eq;
6669 str = var_str_list->text;
6670 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006671 if (!eq) /* stop at first non-assignment */
6672 break;
6673 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006674 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006675 && strncmp(str, name, name_len) == 0
6676 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006677 p = eq;
6678 /* goto value; - WRONG! */
6679 /* think "A=1 A=2 B=$A" */
6680 }
6681 var_str_list = var_str_list->next;
6682 } while (var_str_list);
6683 if (p)
6684 goto value;
6685 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006686 p = lookupvar(name);
6687 value:
6688 if (!p)
6689 return -1;
6690
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006691 len = strtodest(p, syntax, quotes);
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006692#if ENABLE_UNICODE_SUPPORT
6693 if (subtype == VSLENGTH && len > 0) {
6694 reinit_unicode_for_ash();
6695 if (unicode_status == UNICODE_ON) {
6696 len = unicode_strlen(p);
6697 }
6698 }
6699#endif
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006700 break;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006701 }
6702
Ron Yorstond68d1fb2015-05-18 09:49:28 +02006703 if (discard)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006704 STADJUST(-len, expdest);
6705 return len;
6706}
6707
6708/*
6709 * Expand a variable, and return a pointer to the next character in the
6710 * input string.
6711 */
6712static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006713evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006714{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006715 char varflags;
6716 char subtype;
Ron Yorston549deab2015-05-18 09:57:51 +02006717 int quoted;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006718 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006719 char *var;
6720 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006721 int startloc;
6722 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006723
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006724 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006725 subtype = varflags & VSTYPE;
Ron Yorston549deab2015-05-18 09:57:51 +02006726 quoted = flags & EXP_QUOTED;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006727 var = p;
6728 easy = (!quoted || (*var == '@' && shellparam.nparam));
6729 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006730 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006731
6732 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006733 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006734 if (varflags & VSNUL)
6735 varlen--;
6736
6737 if (subtype == VSPLUS) {
6738 varlen = -1 - varlen;
6739 goto vsplus;
6740 }
6741
6742 if (subtype == VSMINUS) {
6743 vsplus:
6744 if (varlen < 0) {
6745 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006746 p,
Ron Yorston549deab2015-05-18 09:57:51 +02006747 flags | EXP_TILDE | EXP_WORD,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006748 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006749 );
6750 goto end;
6751 }
6752 if (easy)
6753 goto record;
6754 goto end;
6755 }
6756
6757 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6758 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006759 if (subevalvar(p, var, /* strloc: */ 0,
6760 subtype, startloc, varflags,
Ron Yorston549deab2015-05-18 09:57:51 +02006761 /* quotes: */ flags & ~QUOTES_ESC,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006762 var_str_list)
6763 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006764 varflags &= ~VSNUL;
6765 /*
6766 * Remove any recorded regions beyond
6767 * start of variable
6768 */
6769 removerecordregions(startloc);
6770 goto again;
6771 }
6772 goto end;
6773 }
6774 if (easy)
6775 goto record;
6776 goto end;
6777 }
6778
6779 if (varlen < 0 && uflag)
6780 varunset(p, var, 0, 0);
6781
6782 if (subtype == VSLENGTH) {
Denys Vlasenkoc76236f2014-12-29 00:04:18 +01006783 cvtnum(varlen > 0 ? varlen : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006784 goto record;
6785 }
6786
6787 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006788 if (easy)
6789 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006790 goto end;
6791 }
6792
6793#if DEBUG
6794 switch (subtype) {
6795 case VSTRIMLEFT:
6796 case VSTRIMLEFTMAX:
6797 case VSTRIMRIGHT:
6798 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006799#if ENABLE_ASH_BASH_COMPAT
6800 case VSSUBSTR:
6801 case VSREPLACE:
6802 case VSREPLACEALL:
6803#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006804 break;
6805 default:
6806 abort();
6807 }
6808#endif
6809
6810 if (varlen >= 0) {
6811 /*
6812 * Terminate the string and start recording the pattern
6813 * right after it
6814 */
6815 STPUTC('\0', expdest);
6816 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006817 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Ron Yorston549deab2015-05-18 09:57:51 +02006818 startloc, varflags, flags, var_str_list)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006819 int amount = expdest - (
6820 (char *)stackblock() + patloc - 1
6821 );
6822 STADJUST(-amount, expdest);
6823 }
6824 /* Remove any recorded regions beyond start of variable */
6825 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006826 record:
6827 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006828 }
6829
6830 end:
6831 if (subtype != VSNORMAL) { /* skip to end of alternative */
6832 int nesting = 1;
6833 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006834 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006835 if (c == CTLESC)
6836 p++;
Ron Yorston549deab2015-05-18 09:57:51 +02006837 else if (c == CTLBACKQ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006838 if (varlen >= 0)
6839 argbackq = argbackq->next;
6840 } else if (c == CTLVAR) {
6841 if ((*p++ & VSTYPE) != VSNORMAL)
6842 nesting++;
6843 } else if (c == CTLENDVAR) {
6844 if (--nesting == 0)
6845 break;
6846 }
6847 }
6848 }
6849 return p;
6850}
6851
6852/*
6853 * Break the argument string into pieces based upon IFS and add the
6854 * strings to the argument list. The regions of the string to be
6855 * searched for IFS characters have been stored by recordregion.
6856 */
6857static void
6858ifsbreakup(char *string, struct arglist *arglist)
6859{
6860 struct ifsregion *ifsp;
6861 struct strlist *sp;
6862 char *start;
6863 char *p;
6864 char *q;
6865 const char *ifs, *realifs;
6866 int ifsspc;
6867 int nulonly;
6868
6869 start = string;
6870 if (ifslastp != NULL) {
6871 ifsspc = 0;
6872 nulonly = 0;
6873 realifs = ifsset() ? ifsval() : defifs;
6874 ifsp = &ifsfirst;
6875 do {
6876 p = string + ifsp->begoff;
6877 nulonly = ifsp->nulonly;
6878 ifs = nulonly ? nullstr : realifs;
6879 ifsspc = 0;
6880 while (p < string + ifsp->endoff) {
6881 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006882 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006883 p++;
6884 if (!strchr(ifs, *p)) {
6885 p++;
6886 continue;
6887 }
6888 if (!nulonly)
6889 ifsspc = (strchr(defifs, *p) != NULL);
6890 /* Ignore IFS whitespace at start */
6891 if (q == start && ifsspc) {
6892 p++;
6893 start = p;
6894 continue;
6895 }
6896 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006897 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006898 sp->text = start;
6899 *arglist->lastp = sp;
6900 arglist->lastp = &sp->next;
6901 p++;
6902 if (!nulonly) {
6903 for (;;) {
6904 if (p >= string + ifsp->endoff) {
6905 break;
6906 }
6907 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006908 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006909 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006910 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006911 p = q;
6912 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006913 }
6914 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006915 if (ifsspc) {
6916 p++;
6917 ifsspc = 0;
6918 } else {
6919 p = q;
6920 break;
6921 }
6922 } else
6923 p++;
6924 }
6925 }
6926 start = p;
6927 } /* while */
6928 ifsp = ifsp->next;
6929 } while (ifsp != NULL);
6930 if (nulonly)
6931 goto add;
6932 }
6933
6934 if (!*start)
6935 return;
6936
6937 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006938 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006939 sp->text = start;
6940 *arglist->lastp = sp;
6941 arglist->lastp = &sp->next;
6942}
6943
6944static void
6945ifsfree(void)
6946{
6947 struct ifsregion *p;
6948
6949 INT_OFF;
6950 p = ifsfirst.next;
6951 do {
6952 struct ifsregion *ifsp;
6953 ifsp = p->next;
6954 free(p);
6955 p = ifsp;
6956 } while (p);
6957 ifslastp = NULL;
6958 ifsfirst.next = NULL;
6959 INT_ON;
6960}
6961
6962/*
6963 * Add a file name to the list.
6964 */
6965static void
6966addfname(const char *name)
6967{
6968 struct strlist *sp;
6969
Denis Vlasenko597906c2008-02-20 16:38:54 +00006970 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006971 sp->text = ststrdup(name);
6972 *exparg.lastp = sp;
6973 exparg.lastp = &sp->next;
6974}
6975
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006976/*
6977 * Do metacharacter (i.e. *, ?, [...]) expansion.
6978 */
6979static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006980expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006981{
6982 char *p;
6983 const char *cp;
6984 char *start;
6985 char *endname;
6986 int metaflag;
6987 struct stat statb;
6988 DIR *dirp;
6989 struct dirent *dp;
6990 int atend;
6991 int matchdot;
Ron Yorstonca25af92015-09-04 10:32:41 +01006992 int esc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006993
6994 metaflag = 0;
6995 start = name;
Ron Yorstonca25af92015-09-04 10:32:41 +01006996 for (p = name; esc = 0, *p; p += esc + 1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006997 if (*p == '*' || *p == '?')
6998 metaflag = 1;
6999 else if (*p == '[') {
7000 char *q = p + 1;
7001 if (*q == '!')
7002 q++;
7003 for (;;) {
7004 if (*q == '\\')
7005 q++;
7006 if (*q == '/' || *q == '\0')
7007 break;
7008 if (*++q == ']') {
7009 metaflag = 1;
7010 break;
7011 }
7012 }
Ron Yorstonca25af92015-09-04 10:32:41 +01007013 } else {
7014 if (*p == '\\')
7015 esc++;
7016 if (p[esc] == '/') {
7017 if (metaflag)
7018 break;
7019 start = p + esc + 1;
7020 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007021 }
7022 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007023 if (metaflag == 0) { /* we've reached the end of the file name */
7024 if (enddir != expdir)
7025 metaflag++;
7026 p = name;
7027 do {
7028 if (*p == '\\')
7029 p++;
7030 *enddir++ = *p;
7031 } while (*p++);
7032 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7033 addfname(expdir);
7034 return;
7035 }
7036 endname = p;
7037 if (name < start) {
7038 p = name;
7039 do {
7040 if (*p == '\\')
7041 p++;
7042 *enddir++ = *p++;
7043 } while (p < start);
7044 }
7045 if (enddir == expdir) {
7046 cp = ".";
7047 } else if (enddir == expdir + 1 && *expdir == '/') {
7048 cp = "/";
7049 } else {
7050 cp = expdir;
7051 enddir[-1] = '\0';
7052 }
7053 dirp = opendir(cp);
7054 if (dirp == NULL)
7055 return;
7056 if (enddir != expdir)
7057 enddir[-1] = '/';
7058 if (*endname == 0) {
7059 atend = 1;
7060 } else {
7061 atend = 0;
Ron Yorstonca25af92015-09-04 10:32:41 +01007062 *endname = '\0';
7063 endname += esc + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007064 }
7065 matchdot = 0;
7066 p = start;
7067 if (*p == '\\')
7068 p++;
7069 if (*p == '.')
7070 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007071 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007072 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007073 continue;
7074 if (pmatch(start, dp->d_name)) {
7075 if (atend) {
7076 strcpy(enddir, dp->d_name);
7077 addfname(expdir);
7078 } else {
7079 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7080 continue;
7081 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007082 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007083 }
7084 }
7085 }
7086 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007087 if (!atend)
Ron Yorstonca25af92015-09-04 10:32:41 +01007088 endname[-esc - 1] = esc ? '\\' : '/';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007089}
7090
7091static struct strlist *
7092msort(struct strlist *list, int len)
7093{
7094 struct strlist *p, *q = NULL;
7095 struct strlist **lpp;
7096 int half;
7097 int n;
7098
7099 if (len <= 1)
7100 return list;
7101 half = len >> 1;
7102 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007103 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007104 q = p;
7105 p = p->next;
7106 }
7107 q->next = NULL; /* terminate first half of list */
7108 q = msort(list, half); /* sort first half of list */
7109 p = msort(p, len - half); /* sort second half */
7110 lpp = &list;
7111 for (;;) {
7112#if ENABLE_LOCALE_SUPPORT
7113 if (strcoll(p->text, q->text) < 0)
7114#else
7115 if (strcmp(p->text, q->text) < 0)
7116#endif
7117 {
7118 *lpp = p;
7119 lpp = &p->next;
7120 p = *lpp;
7121 if (p == NULL) {
7122 *lpp = q;
7123 break;
7124 }
7125 } else {
7126 *lpp = q;
7127 lpp = &q->next;
7128 q = *lpp;
7129 if (q == NULL) {
7130 *lpp = p;
7131 break;
7132 }
7133 }
7134 }
7135 return list;
7136}
7137
7138/*
7139 * Sort the results of file name expansion. It calculates the number of
7140 * strings to sort and then calls msort (short for merge sort) to do the
7141 * work.
7142 */
7143static struct strlist *
7144expsort(struct strlist *str)
7145{
7146 int len;
7147 struct strlist *sp;
7148
7149 len = 0;
7150 for (sp = str; sp; sp = sp->next)
7151 len++;
7152 return msort(str, len);
7153}
7154
7155static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007156expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007157{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007158 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007159 '*', '?', '[', 0
7160 };
7161 /* TODO - EXP_REDIR */
7162
7163 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007164 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007165 struct strlist **savelastp;
7166 struct strlist *sp;
7167 char *p;
7168
7169 if (fflag)
7170 goto nometa;
7171 if (!strpbrk(str->text, metachars))
7172 goto nometa;
7173 savelastp = exparg.lastp;
7174
7175 INT_OFF;
Ron Yorston549deab2015-05-18 09:57:51 +02007176 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007177 {
7178 int i = strlen(str->text);
7179 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7180 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007181 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007182 free(expdir);
7183 if (p != str->text)
7184 free(p);
7185 INT_ON;
7186 if (exparg.lastp == savelastp) {
7187 /*
7188 * no matches
7189 */
7190 nometa:
7191 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007192 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007193 exparg.lastp = &str->next;
7194 } else {
7195 *exparg.lastp = NULL;
7196 *savelastp = sp = expsort(*savelastp);
7197 while (sp->next != NULL)
7198 sp = sp->next;
7199 exparg.lastp = &sp->next;
7200 }
7201 str = str->next;
7202 }
7203}
7204
7205/*
7206 * Perform variable substitution and command substitution on an argument,
7207 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7208 * perform splitting and file name expansion. When arglist is NULL, perform
7209 * here document expansion.
7210 */
7211static void
7212expandarg(union node *arg, struct arglist *arglist, int flag)
7213{
7214 struct strlist *sp;
7215 char *p;
7216
7217 argbackq = arg->narg.backquote;
7218 STARTSTACKSTR(expdest);
7219 ifsfirst.next = NULL;
7220 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007221 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007222 argstr(arg->narg.text, flag,
7223 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007224 p = _STPUTC('\0', expdest);
7225 expdest = p - 1;
7226 if (arglist == NULL) {
7227 return; /* here document expanded */
7228 }
7229 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007230 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007231 exparg.lastp = &exparg.list;
7232 /*
7233 * TODO - EXP_REDIR
7234 */
7235 if (flag & EXP_FULL) {
7236 ifsbreakup(p, &exparg);
7237 *exparg.lastp = NULL;
7238 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007239 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007240 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007241 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007242 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007243 TRACE(("expandarg: rmescapes:'%s'\n", p));
7244 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007245 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007246 sp->text = p;
7247 *exparg.lastp = sp;
7248 exparg.lastp = &sp->next;
7249 }
7250 if (ifsfirst.next)
7251 ifsfree();
7252 *exparg.lastp = NULL;
7253 if (exparg.list) {
7254 *arglist->lastp = exparg.list;
7255 arglist->lastp = exparg.lastp;
7256 }
7257}
7258
7259/*
7260 * Expand shell variables and backquotes inside a here document.
7261 */
7262static void
7263expandhere(union node *arg, int fd)
7264{
7265 herefd = fd;
Ron Yorston549deab2015-05-18 09:57:51 +02007266 expandarg(arg, (struct arglist *)NULL, EXP_QUOTED);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007267 full_write(fd, stackblock(), expdest - (char *)stackblock());
7268}
7269
7270/*
7271 * Returns true if the pattern matches the string.
7272 */
7273static int
7274patmatch(char *pattern, const char *string)
7275{
Ron Yorston549deab2015-05-18 09:57:51 +02007276 return pmatch(preglob(pattern, 0), string);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007277}
7278
7279/*
7280 * See if a pattern matches in a case statement.
7281 */
7282static int
7283casematch(union node *pattern, char *val)
7284{
7285 struct stackmark smark;
7286 int result;
7287
7288 setstackmark(&smark);
7289 argbackq = pattern->narg.backquote;
7290 STARTSTACKSTR(expdest);
7291 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007292 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7293 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007294 STACKSTRNUL(expdest);
7295 result = patmatch(stackblock(), val);
7296 popstackmark(&smark);
7297 return result;
7298}
7299
7300
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007301/* ============ find_command */
7302
7303struct builtincmd {
7304 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007305 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007306 /* unsigned flags; */
7307};
7308#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007309/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007310 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007311#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007312#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007313
7314struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007315 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007316 union param {
7317 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007318 /* index >= 0 for commands without path (slashes) */
7319 /* (TODO: what exactly does the value mean? PATH position?) */
7320 /* index == -1 for commands with slashes */
7321 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007322 const struct builtincmd *cmd;
7323 struct funcnode *func;
7324 } u;
7325};
7326/* values of cmdtype */
7327#define CMDUNKNOWN -1 /* no entry in table for command */
7328#define CMDNORMAL 0 /* command is an executable program */
7329#define CMDFUNCTION 1 /* command is a shell function */
7330#define CMDBUILTIN 2 /* command is a shell builtin */
7331
7332/* action to find_command() */
7333#define DO_ERR 0x01 /* prints errors */
7334#define DO_ABS 0x02 /* checks absolute paths */
7335#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7336#define DO_ALTPATH 0x08 /* using alternate path */
7337#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7338
7339static void find_command(char *, struct cmdentry *, int, const char *);
7340
7341
7342/* ============ Hashing commands */
7343
7344/*
7345 * When commands are first encountered, they are entered in a hash table.
7346 * This ensures that a full path search will not have to be done for them
7347 * on each invocation.
7348 *
7349 * We should investigate converting to a linear search, even though that
7350 * would make the command name "hash" a misnomer.
7351 */
7352
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007353struct tblentry {
7354 struct tblentry *next; /* next entry in hash chain */
7355 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007356 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007357 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007358 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007359};
7360
Denis Vlasenko01631112007-12-16 17:20:38 +00007361static struct tblentry **cmdtable;
7362#define INIT_G_cmdtable() do { \
7363 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7364} while (0)
7365
7366static int builtinloc = -1; /* index in path of %builtin, or -1 */
7367
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007368
7369static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007370tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007371{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007372#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007373 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007374 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007375 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007376 while (*envp)
7377 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007378 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007379 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007380 /* re-exec ourselves with the new arguments */
7381 execve(bb_busybox_exec_path, argv, envp);
7382 /* If they called chroot or otherwise made the binary no longer
7383 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007384 }
7385#endif
7386
7387 repeat:
7388#ifdef SYSV
7389 do {
7390 execve(cmd, argv, envp);
7391 } while (errno == EINTR);
7392#else
7393 execve(cmd, argv, envp);
7394#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007395 if (cmd == (char*) bb_busybox_exec_path) {
7396 /* We already visited ENOEXEC branch below, don't do it again */
7397//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007398 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007399 return;
7400 }
7401 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007402 /* Run "cmd" as a shell script:
7403 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7404 * "If the execve() function fails with ENOEXEC, the shell
7405 * shall execute a command equivalent to having a shell invoked
7406 * with the command name as its first operand,
7407 * with any remaining arguments passed to the new shell"
7408 *
7409 * That is, do not use $SHELL, user's shell, or /bin/sh;
7410 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007411 *
7412 * Note that bash reads ~80 chars of the file, and if it sees
7413 * a zero byte before it sees newline, it doesn't try to
7414 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007415 * message and exit code 126. For one, this prevents attempts
7416 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007417 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007418 char **ap;
7419 char **new;
7420
7421 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007422 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007423 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7424 new[0] = (char*) "ash";
7425 new[1] = cmd;
7426 ap = new + 2;
7427 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007428 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007429 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007430 argv = new;
7431 goto repeat;
7432 }
7433}
7434
7435/*
7436 * Exec a program. Never returns. If you change this routine, you may
7437 * have to change the find_command routine as well.
7438 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007439static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007440static void
7441shellexec(char **argv, const char *path, int idx)
7442{
7443 char *cmdname;
7444 int e;
7445 char **envp;
7446 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007447 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007448
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007449 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007450 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007451 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007452#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007453 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007454#endif
7455 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007456 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007457 if (applet_no >= 0) {
7458 /* We tried execing ourself, but it didn't work.
7459 * Maybe /proc/self/exe doesn't exist?
7460 * Try $PATH search.
7461 */
7462 goto try_PATH;
7463 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007464 e = errno;
7465 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007466 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007467 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007468 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007469 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007470 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007471 if (errno != ENOENT && errno != ENOTDIR)
7472 e = errno;
7473 }
7474 stunalloc(cmdname);
7475 }
7476 }
7477
7478 /* Map to POSIX errors */
7479 switch (e) {
7480 case EACCES:
7481 exerrno = 126;
7482 break;
7483 case ENOENT:
7484 exerrno = 127;
7485 break;
7486 default:
7487 exerrno = 2;
7488 break;
7489 }
7490 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007491 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7492 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007493 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7494 /* NOTREACHED */
7495}
7496
7497static void
7498printentry(struct tblentry *cmdp)
7499{
7500 int idx;
7501 const char *path;
7502 char *name;
7503
7504 idx = cmdp->param.index;
7505 path = pathval();
7506 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007507 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007508 stunalloc(name);
7509 } while (--idx >= 0);
7510 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7511}
7512
7513/*
7514 * Clear out command entries. The argument specifies the first entry in
7515 * PATH which has changed.
7516 */
7517static void
7518clearcmdentry(int firstchange)
7519{
7520 struct tblentry **tblp;
7521 struct tblentry **pp;
7522 struct tblentry *cmdp;
7523
7524 INT_OFF;
7525 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7526 pp = tblp;
7527 while ((cmdp = *pp) != NULL) {
7528 if ((cmdp->cmdtype == CMDNORMAL &&
7529 cmdp->param.index >= firstchange)
7530 || (cmdp->cmdtype == CMDBUILTIN &&
7531 builtinloc >= firstchange)
7532 ) {
7533 *pp = cmdp->next;
7534 free(cmdp);
7535 } else {
7536 pp = &cmdp->next;
7537 }
7538 }
7539 }
7540 INT_ON;
7541}
7542
7543/*
7544 * Locate a command in the command hash table. If "add" is nonzero,
7545 * add the command to the table if it is not already present. The
7546 * variable "lastcmdentry" is set to point to the address of the link
7547 * pointing to the entry, so that delete_cmd_entry can delete the
7548 * entry.
7549 *
7550 * Interrupts must be off if called with add != 0.
7551 */
7552static struct tblentry **lastcmdentry;
7553
7554static struct tblentry *
7555cmdlookup(const char *name, int add)
7556{
7557 unsigned int hashval;
7558 const char *p;
7559 struct tblentry *cmdp;
7560 struct tblentry **pp;
7561
7562 p = name;
7563 hashval = (unsigned char)*p << 4;
7564 while (*p)
7565 hashval += (unsigned char)*p++;
7566 hashval &= 0x7FFF;
7567 pp = &cmdtable[hashval % CMDTABLESIZE];
7568 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7569 if (strcmp(cmdp->cmdname, name) == 0)
7570 break;
7571 pp = &cmdp->next;
7572 }
7573 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007574 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7575 + strlen(name)
7576 /* + 1 - already done because
7577 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007578 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007579 cmdp->cmdtype = CMDUNKNOWN;
7580 strcpy(cmdp->cmdname, name);
7581 }
7582 lastcmdentry = pp;
7583 return cmdp;
7584}
7585
7586/*
7587 * Delete the command entry returned on the last lookup.
7588 */
7589static void
7590delete_cmd_entry(void)
7591{
7592 struct tblentry *cmdp;
7593
7594 INT_OFF;
7595 cmdp = *lastcmdentry;
7596 *lastcmdentry = cmdp->next;
7597 if (cmdp->cmdtype == CMDFUNCTION)
7598 freefunc(cmdp->param.func);
7599 free(cmdp);
7600 INT_ON;
7601}
7602
7603/*
7604 * Add a new command entry, replacing any existing command entry for
7605 * the same name - except special builtins.
7606 */
7607static void
7608addcmdentry(char *name, struct cmdentry *entry)
7609{
7610 struct tblentry *cmdp;
7611
7612 cmdp = cmdlookup(name, 1);
7613 if (cmdp->cmdtype == CMDFUNCTION) {
7614 freefunc(cmdp->param.func);
7615 }
7616 cmdp->cmdtype = entry->cmdtype;
7617 cmdp->param = entry->u;
7618 cmdp->rehash = 0;
7619}
7620
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007621static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007622hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007623{
7624 struct tblentry **pp;
7625 struct tblentry *cmdp;
7626 int c;
7627 struct cmdentry entry;
7628 char *name;
7629
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007630 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007631 clearcmdentry(0);
7632 return 0;
7633 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007634
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007635 if (*argptr == NULL) {
7636 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7637 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7638 if (cmdp->cmdtype == CMDNORMAL)
7639 printentry(cmdp);
7640 }
7641 }
7642 return 0;
7643 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007644
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007645 c = 0;
7646 while ((name = *argptr) != NULL) {
7647 cmdp = cmdlookup(name, 0);
7648 if (cmdp != NULL
7649 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007650 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7651 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007652 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007653 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007654 find_command(name, &entry, DO_ERR, pathval());
7655 if (entry.cmdtype == CMDUNKNOWN)
7656 c = 1;
7657 argptr++;
7658 }
7659 return c;
7660}
7661
7662/*
7663 * Called when a cd is done. Marks all commands so the next time they
7664 * are executed they will be rehashed.
7665 */
7666static void
7667hashcd(void)
7668{
7669 struct tblentry **pp;
7670 struct tblentry *cmdp;
7671
7672 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7673 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007674 if (cmdp->cmdtype == CMDNORMAL
7675 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007676 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007677 && builtinloc > 0)
7678 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007679 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007680 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007681 }
7682 }
7683}
7684
7685/*
7686 * Fix command hash table when PATH changed.
7687 * Called before PATH is changed. The argument is the new value of PATH;
7688 * pathval() still returns the old value at this point.
7689 * Called with interrupts off.
7690 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007691static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007692changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007693{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007694 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007695 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007696 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007697 int idx_bltin;
7698
7699 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007700 firstchange = 9999; /* assume no change */
7701 idx = 0;
7702 idx_bltin = -1;
7703 for (;;) {
7704 if (*old != *new) {
7705 firstchange = idx;
7706 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007707 || (*old == ':' && *new == '\0')
7708 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007709 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007710 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007711 old = new; /* ignore subsequent differences */
7712 }
7713 if (*new == '\0')
7714 break;
7715 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7716 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007717 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007718 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007719 new++;
7720 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007721 }
7722 if (builtinloc < 0 && idx_bltin >= 0)
7723 builtinloc = idx_bltin; /* zap builtins */
7724 if (builtinloc >= 0 && idx_bltin < 0)
7725 firstchange = 0;
7726 clearcmdentry(firstchange);
7727 builtinloc = idx_bltin;
7728}
7729
7730#define TEOF 0
7731#define TNL 1
7732#define TREDIR 2
7733#define TWORD 3
7734#define TSEMI 4
7735#define TBACKGND 5
7736#define TAND 6
7737#define TOR 7
7738#define TPIPE 8
7739#define TLP 9
7740#define TRP 10
7741#define TENDCASE 11
7742#define TENDBQUOTE 12
7743#define TNOT 13
7744#define TCASE 14
7745#define TDO 15
7746#define TDONE 16
7747#define TELIF 17
7748#define TELSE 18
7749#define TESAC 19
7750#define TFI 20
7751#define TFOR 21
7752#define TIF 22
7753#define TIN 23
7754#define TTHEN 24
7755#define TUNTIL 25
7756#define TWHILE 26
7757#define TBEGIN 27
7758#define TEND 28
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007759typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007760
7761/* first char is indicating which tokens mark the end of a list */
7762static const char *const tokname_array[] = {
7763 "\1end of file",
7764 "\0newline",
7765 "\0redirection",
7766 "\0word",
7767 "\0;",
7768 "\0&",
7769 "\0&&",
7770 "\0||",
7771 "\0|",
7772 "\0(",
7773 "\1)",
7774 "\1;;",
7775 "\1`",
7776#define KWDOFFSET 13
7777 /* the following are keywords */
7778 "\0!",
7779 "\0case",
7780 "\1do",
7781 "\1done",
7782 "\1elif",
7783 "\1else",
7784 "\1esac",
7785 "\1fi",
7786 "\0for",
7787 "\0if",
7788 "\0in",
7789 "\1then",
7790 "\0until",
7791 "\0while",
7792 "\0{",
7793 "\1}",
7794};
7795
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007796/* Wrapper around strcmp for qsort/bsearch/... */
7797static int
7798pstrcmp(const void *a, const void *b)
7799{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007800 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007801}
7802
7803static const char *const *
7804findkwd(const char *s)
7805{
7806 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007807 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7808 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007809}
7810
7811/*
7812 * Locate and print what a word is...
7813 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007814static int
Ron Yorston3f221112015-08-03 13:47:33 +01007815describe_command(char *command, const char *path, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007816{
7817 struct cmdentry entry;
7818 struct tblentry *cmdp;
7819#if ENABLE_ASH_ALIAS
7820 const struct alias *ap;
7821#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007822
7823 path = path ? path : pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007824
7825 if (describe_command_verbose) {
7826 out1str(command);
7827 }
7828
7829 /* First look at the keywords */
7830 if (findkwd(command)) {
7831 out1str(describe_command_verbose ? " is a shell keyword" : command);
7832 goto out;
7833 }
7834
7835#if ENABLE_ASH_ALIAS
7836 /* Then look at the aliases */
7837 ap = lookupalias(command, 0);
7838 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007839 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007840 out1str("alias ");
7841 printalias(ap);
7842 return 0;
7843 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007844 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007845 goto out;
7846 }
7847#endif
7848 /* Then check if it is a tracked alias */
7849 cmdp = cmdlookup(command, 0);
7850 if (cmdp != NULL) {
7851 entry.cmdtype = cmdp->cmdtype;
7852 entry.u = cmdp->param;
7853 } else {
7854 /* Finally use brute force */
7855 find_command(command, &entry, DO_ABS, path);
7856 }
7857
7858 switch (entry.cmdtype) {
7859 case CMDNORMAL: {
7860 int j = entry.u.index;
7861 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007862 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007863 p = command;
7864 } else {
7865 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007866 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007867 stunalloc(p);
7868 } while (--j >= 0);
7869 }
7870 if (describe_command_verbose) {
7871 out1fmt(" is%s %s",
7872 (cmdp ? " a tracked alias for" : nullstr), p
7873 );
7874 } else {
7875 out1str(p);
7876 }
7877 break;
7878 }
7879
7880 case CMDFUNCTION:
7881 if (describe_command_verbose) {
7882 out1str(" is a shell function");
7883 } else {
7884 out1str(command);
7885 }
7886 break;
7887
7888 case CMDBUILTIN:
7889 if (describe_command_verbose) {
7890 out1fmt(" is a %sshell builtin",
7891 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7892 "special " : nullstr
7893 );
7894 } else {
7895 out1str(command);
7896 }
7897 break;
7898
7899 default:
7900 if (describe_command_verbose) {
7901 out1str(": not found\n");
7902 }
7903 return 127;
7904 }
7905 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01007906 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007907 return 0;
7908}
7909
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007910static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007911typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007912{
Denis Vlasenko46846e22007-05-20 13:08:31 +00007913 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007914 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00007915 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007916
Denis Vlasenko46846e22007-05-20 13:08:31 +00007917 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00007918 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007919 i++;
7920 verbose = 0;
7921 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00007922 while (argv[i]) {
Ron Yorston3f221112015-08-03 13:47:33 +01007923 err |= describe_command(argv[i++], NULL, verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007924 }
7925 return err;
7926}
7927
7928#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007929static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007930commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007931{
7932 int c;
7933 enum {
7934 VERIFY_BRIEF = 1,
7935 VERIFY_VERBOSE = 2,
7936 } verify = 0;
Ron Yorston3f221112015-08-03 13:47:33 +01007937 const char *path = NULL;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007938
7939 while ((c = nextopt("pvV")) != '\0')
7940 if (c == 'V')
7941 verify |= VERIFY_VERBOSE;
7942 else if (c == 'v')
7943 verify |= VERIFY_BRIEF;
7944#if DEBUG
7945 else if (c != 'p')
7946 abort();
7947#endif
Ron Yorston3f221112015-08-03 13:47:33 +01007948 else
7949 path = bb_default_path;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007950 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
7951 if (verify && (*argptr != NULL)) {
Ron Yorston3f221112015-08-03 13:47:33 +01007952 return describe_command(*argptr, path, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00007953 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007954
7955 return 0;
7956}
7957#endif
7958
7959
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007960/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00007961
Denis Vlasenko340299a2008-11-21 10:36:36 +00007962static int funcblocksize; /* size of structures in function */
7963static int funcstringsize; /* size of strings in node */
7964static void *funcblock; /* block to allocate function from */
7965static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007966
Eric Andersencb57d552001-06-28 07:25:16 +00007967/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00007968#define EV_EXIT 01 /* exit after evaluating tree */
7969#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersenc470f442003-07-28 09:56:35 +00007970#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00007971
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02007972static const uint8_t nodesize[N_NUMBER] = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00007973 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
7974 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
7975 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
7976 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
7977 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
7978 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
7979 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
7980 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
7981 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
7982 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
7983 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
7984 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
7985 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
7986 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
7987 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
7988 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
7989 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00007990#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00007991 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00007992#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00007993 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
7994 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
7995 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
7996 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
7997 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7998 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
7999 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8000 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8001 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008002};
8003
8004static void calcsize(union node *n);
8005
8006static void
8007sizenodelist(struct nodelist *lp)
8008{
8009 while (lp) {
8010 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8011 calcsize(lp->n);
8012 lp = lp->next;
8013 }
8014}
8015
8016static void
8017calcsize(union node *n)
8018{
8019 if (n == NULL)
8020 return;
8021 funcblocksize += nodesize[n->type];
8022 switch (n->type) {
8023 case NCMD:
8024 calcsize(n->ncmd.redirect);
8025 calcsize(n->ncmd.args);
8026 calcsize(n->ncmd.assign);
8027 break;
8028 case NPIPE:
8029 sizenodelist(n->npipe.cmdlist);
8030 break;
8031 case NREDIR:
8032 case NBACKGND:
8033 case NSUBSHELL:
8034 calcsize(n->nredir.redirect);
8035 calcsize(n->nredir.n);
8036 break;
8037 case NAND:
8038 case NOR:
8039 case NSEMI:
8040 case NWHILE:
8041 case NUNTIL:
8042 calcsize(n->nbinary.ch2);
8043 calcsize(n->nbinary.ch1);
8044 break;
8045 case NIF:
8046 calcsize(n->nif.elsepart);
8047 calcsize(n->nif.ifpart);
8048 calcsize(n->nif.test);
8049 break;
8050 case NFOR:
8051 funcstringsize += strlen(n->nfor.var) + 1;
8052 calcsize(n->nfor.body);
8053 calcsize(n->nfor.args);
8054 break;
8055 case NCASE:
8056 calcsize(n->ncase.cases);
8057 calcsize(n->ncase.expr);
8058 break;
8059 case NCLIST:
8060 calcsize(n->nclist.body);
8061 calcsize(n->nclist.pattern);
8062 calcsize(n->nclist.next);
8063 break;
8064 case NDEFUN:
8065 case NARG:
8066 sizenodelist(n->narg.backquote);
8067 funcstringsize += strlen(n->narg.text) + 1;
8068 calcsize(n->narg.next);
8069 break;
8070 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008071#if ENABLE_ASH_BASH_COMPAT
8072 case NTO2:
8073#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008074 case NCLOBBER:
8075 case NFROM:
8076 case NFROMTO:
8077 case NAPPEND:
8078 calcsize(n->nfile.fname);
8079 calcsize(n->nfile.next);
8080 break;
8081 case NTOFD:
8082 case NFROMFD:
8083 calcsize(n->ndup.vname);
8084 calcsize(n->ndup.next);
8085 break;
8086 case NHERE:
8087 case NXHERE:
8088 calcsize(n->nhere.doc);
8089 calcsize(n->nhere.next);
8090 break;
8091 case NNOT:
8092 calcsize(n->nnot.com);
8093 break;
8094 };
8095}
8096
8097static char *
8098nodeckstrdup(char *s)
8099{
8100 char *rtn = funcstring;
8101
8102 strcpy(funcstring, s);
8103 funcstring += strlen(s) + 1;
8104 return rtn;
8105}
8106
8107static union node *copynode(union node *);
8108
8109static struct nodelist *
8110copynodelist(struct nodelist *lp)
8111{
8112 struct nodelist *start;
8113 struct nodelist **lpp;
8114
8115 lpp = &start;
8116 while (lp) {
8117 *lpp = funcblock;
8118 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8119 (*lpp)->n = copynode(lp->n);
8120 lp = lp->next;
8121 lpp = &(*lpp)->next;
8122 }
8123 *lpp = NULL;
8124 return start;
8125}
8126
8127static union node *
8128copynode(union node *n)
8129{
8130 union node *new;
8131
8132 if (n == NULL)
8133 return NULL;
8134 new = funcblock;
8135 funcblock = (char *) funcblock + nodesize[n->type];
8136
8137 switch (n->type) {
8138 case NCMD:
8139 new->ncmd.redirect = copynode(n->ncmd.redirect);
8140 new->ncmd.args = copynode(n->ncmd.args);
8141 new->ncmd.assign = copynode(n->ncmd.assign);
8142 break;
8143 case NPIPE:
8144 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008145 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008146 break;
8147 case NREDIR:
8148 case NBACKGND:
8149 case NSUBSHELL:
8150 new->nredir.redirect = copynode(n->nredir.redirect);
8151 new->nredir.n = copynode(n->nredir.n);
8152 break;
8153 case NAND:
8154 case NOR:
8155 case NSEMI:
8156 case NWHILE:
8157 case NUNTIL:
8158 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8159 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8160 break;
8161 case NIF:
8162 new->nif.elsepart = copynode(n->nif.elsepart);
8163 new->nif.ifpart = copynode(n->nif.ifpart);
8164 new->nif.test = copynode(n->nif.test);
8165 break;
8166 case NFOR:
8167 new->nfor.var = nodeckstrdup(n->nfor.var);
8168 new->nfor.body = copynode(n->nfor.body);
8169 new->nfor.args = copynode(n->nfor.args);
8170 break;
8171 case NCASE:
8172 new->ncase.cases = copynode(n->ncase.cases);
8173 new->ncase.expr = copynode(n->ncase.expr);
8174 break;
8175 case NCLIST:
8176 new->nclist.body = copynode(n->nclist.body);
8177 new->nclist.pattern = copynode(n->nclist.pattern);
8178 new->nclist.next = copynode(n->nclist.next);
8179 break;
8180 case NDEFUN:
8181 case NARG:
8182 new->narg.backquote = copynodelist(n->narg.backquote);
8183 new->narg.text = nodeckstrdup(n->narg.text);
8184 new->narg.next = copynode(n->narg.next);
8185 break;
8186 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008187#if ENABLE_ASH_BASH_COMPAT
8188 case NTO2:
8189#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008190 case NCLOBBER:
8191 case NFROM:
8192 case NFROMTO:
8193 case NAPPEND:
8194 new->nfile.fname = copynode(n->nfile.fname);
8195 new->nfile.fd = n->nfile.fd;
8196 new->nfile.next = copynode(n->nfile.next);
8197 break;
8198 case NTOFD:
8199 case NFROMFD:
8200 new->ndup.vname = copynode(n->ndup.vname);
8201 new->ndup.dupfd = n->ndup.dupfd;
8202 new->ndup.fd = n->ndup.fd;
8203 new->ndup.next = copynode(n->ndup.next);
8204 break;
8205 case NHERE:
8206 case NXHERE:
8207 new->nhere.doc = copynode(n->nhere.doc);
8208 new->nhere.fd = n->nhere.fd;
8209 new->nhere.next = copynode(n->nhere.next);
8210 break;
8211 case NNOT:
8212 new->nnot.com = copynode(n->nnot.com);
8213 break;
8214 };
8215 new->type = n->type;
8216 return new;
8217}
8218
8219/*
8220 * Make a copy of a parse tree.
8221 */
8222static struct funcnode *
8223copyfunc(union node *n)
8224{
8225 struct funcnode *f;
8226 size_t blocksize;
8227
8228 funcblocksize = offsetof(struct funcnode, n);
8229 funcstringsize = 0;
8230 calcsize(n);
8231 blocksize = funcblocksize;
8232 f = ckmalloc(blocksize + funcstringsize);
8233 funcblock = (char *) f + offsetof(struct funcnode, n);
8234 funcstring = (char *) f + blocksize;
8235 copynode(n);
8236 f->count = 0;
8237 return f;
8238}
8239
8240/*
8241 * Define a shell function.
8242 */
8243static void
8244defun(char *name, union node *func)
8245{
8246 struct cmdentry entry;
8247
8248 INT_OFF;
8249 entry.cmdtype = CMDFUNCTION;
8250 entry.u.func = copyfunc(func);
8251 addcmdentry(name, &entry);
8252 INT_ON;
8253}
8254
Denis Vlasenko4b875702009-03-19 13:30:04 +00008255/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008256#define SKIPBREAK (1 << 0)
8257#define SKIPCONT (1 << 1)
8258#define SKIPFUNC (1 << 2)
8259#define SKIPFILE (1 << 3)
8260#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008261static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008262static int skipcount; /* number of levels to skip */
8263static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008264static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008265
Denis Vlasenko4b875702009-03-19 13:30:04 +00008266/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008267static int evalstring(char *s, int mask);
8268
Denis Vlasenko4b875702009-03-19 13:30:04 +00008269/* Called to execute a trap.
8270 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008271 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008272 *
8273 * Perhaps we should avoid entering new trap handlers
8274 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008275 */
8276static int
8277dotrap(void)
8278{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008279 uint8_t *g;
8280 int sig;
8281 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008282
8283 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008284 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008285 xbarrier();
8286
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008287 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008288 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8289 int want_exexit;
8290 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008291
Denis Vlasenko4b875702009-03-19 13:30:04 +00008292 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008293 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008294 t = trap[sig];
8295 /* non-trapped SIGINT is handled separately by raise_interrupt,
8296 * don't upset it by resetting gotsig[SIGINT-1] */
8297 if (sig == SIGINT && !t)
8298 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008299
8300 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008301 *g = 0;
8302 if (!t)
8303 continue;
8304 want_exexit = evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008305 exitstatus = savestatus;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008306 if (want_exexit) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008307 TRACE(("dotrap returns %d\n", want_exexit));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008308 return want_exexit;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008309 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008310 }
8311
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008312 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008313 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008314}
8315
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008316/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008317static void evalloop(union node *, int);
8318static void evalfor(union node *, int);
8319static void evalcase(union node *, int);
8320static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008321static void expredir(union node *);
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008322static void evalpipe(union node *, int);
8323static void evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008324static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008325static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008326
Eric Andersen62483552001-07-10 06:09:16 +00008327/*
Eric Andersenc470f442003-07-28 09:56:35 +00008328 * Evaluate a parse tree. The value is left in the global variable
8329 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008330 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008331static void
Eric Andersenc470f442003-07-28 09:56:35 +00008332evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008333{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008334 struct jmploc *volatile savehandler = exception_handler;
8335 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008336 int checkexit = 0;
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008337 void (*evalfn)(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008338 int status;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008339 int int_level;
8340
8341 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008342
Eric Andersenc470f442003-07-28 09:56:35 +00008343 if (n == NULL) {
8344 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008345 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008346 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008347 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008348
8349 exception_handler = &jmploc;
8350 {
8351 int err = setjmp(jmploc.loc);
8352 if (err) {
8353 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008354 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008355 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8356 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008357 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008358 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008359 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008360 TRACE(("exception %d in evaltree, propagating err=%d\n",
8361 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008362 exception_handler = savehandler;
8363 longjmp(exception_handler->loc, err);
8364 }
8365 }
8366
Eric Andersenc470f442003-07-28 09:56:35 +00008367 switch (n->type) {
8368 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008369#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008370 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008371 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008372 break;
8373#endif
8374 case NNOT:
8375 evaltree(n->nnot.com, EV_TESTED);
8376 status = !exitstatus;
8377 goto setstatus;
8378 case NREDIR:
8379 expredir(n->nredir.redirect);
8380 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8381 if (!status) {
8382 evaltree(n->nredir.n, flags & EV_TESTED);
8383 status = exitstatus;
8384 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008385 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008386 goto setstatus;
8387 case NCMD:
8388 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008389 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008390 if (eflag && !(flags & EV_TESTED))
8391 checkexit = ~0;
8392 goto calleval;
8393 case NFOR:
8394 evalfn = evalfor;
8395 goto calleval;
8396 case NWHILE:
8397 case NUNTIL:
8398 evalfn = evalloop;
8399 goto calleval;
8400 case NSUBSHELL:
8401 case NBACKGND:
8402 evalfn = evalsubshell;
8403 goto calleval;
8404 case NPIPE:
8405 evalfn = evalpipe;
8406 goto checkexit;
8407 case NCASE:
8408 evalfn = evalcase;
8409 goto calleval;
8410 case NAND:
8411 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008412 case NSEMI: {
8413
Eric Andersenc470f442003-07-28 09:56:35 +00008414#if NAND + 1 != NOR
8415#error NAND + 1 != NOR
8416#endif
8417#if NOR + 1 != NSEMI
8418#error NOR + 1 != NSEMI
8419#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008420 unsigned is_or = n->type - NAND;
Eric Andersenc470f442003-07-28 09:56:35 +00008421 evaltree(
8422 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008423 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008424 );
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008425 if (!exitstatus == is_or)
Eric Andersenc470f442003-07-28 09:56:35 +00008426 break;
8427 if (!evalskip) {
8428 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008429 evaln:
Eric Andersenc470f442003-07-28 09:56:35 +00008430 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008431 calleval:
Eric Andersenc470f442003-07-28 09:56:35 +00008432 evalfn(n, flags);
8433 break;
8434 }
8435 break;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008436 }
Eric Andersenc470f442003-07-28 09:56:35 +00008437 case NIF:
8438 evaltree(n->nif.test, EV_TESTED);
8439 if (evalskip)
8440 break;
8441 if (exitstatus == 0) {
8442 n = n->nif.ifpart;
8443 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008444 }
8445 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008446 n = n->nif.elsepart;
8447 goto evaln;
8448 }
8449 goto success;
8450 case NDEFUN:
8451 defun(n->narg.text, n->narg.next);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008452 success:
Eric Andersenc470f442003-07-28 09:56:35 +00008453 status = 0;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008454 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008455 exitstatus = status;
8456 break;
8457 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008458
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008459 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008460 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008461
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008462 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008463 /* Order of checks below is important:
8464 * signal handlers trigger before exit caused by "set -e".
8465 */
8466 if (pending_sig && dotrap())
8467 goto exexit;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008468 if (checkexit & exitstatus)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008469 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008470
8471 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008472 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008473 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008474 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008475
8476 RESTORE_INT(int_level);
8477 TRACE(("leaving evaltree (no interrupts)\n"));
Eric Andersen62483552001-07-10 06:09:16 +00008478}
8479
Eric Andersenc470f442003-07-28 09:56:35 +00008480#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8481static
8482#endif
8483void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8484
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008485static void
Eric Andersenc470f442003-07-28 09:56:35 +00008486evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008487{
8488 int status;
8489
8490 loopnest++;
8491 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008492 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008493 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008494 int i;
8495
Eric Andersencb57d552001-06-28 07:25:16 +00008496 evaltree(n->nbinary.ch1, EV_TESTED);
8497 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008498 skipping:
8499 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008500 evalskip = 0;
8501 continue;
8502 }
8503 if (evalskip == SKIPBREAK && --skipcount <= 0)
8504 evalskip = 0;
8505 break;
8506 }
Eric Andersenc470f442003-07-28 09:56:35 +00008507 i = exitstatus;
8508 if (n->type != NWHILE)
8509 i = !i;
8510 if (i != 0)
8511 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008512 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008513 status = exitstatus;
8514 if (evalskip)
8515 goto skipping;
8516 }
8517 loopnest--;
8518 exitstatus = status;
8519}
8520
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008521static void
Eric Andersenc470f442003-07-28 09:56:35 +00008522evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008523{
8524 struct arglist arglist;
8525 union node *argp;
8526 struct strlist *sp;
8527 struct stackmark smark;
8528
8529 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008530 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008531 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008532 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Ron Yorston549deab2015-05-18 09:57:51 +02008533 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008534 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008535 if (evalskip)
8536 goto out;
8537 }
8538 *arglist.lastp = NULL;
8539
8540 exitstatus = 0;
8541 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008542 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008543 for (sp = arglist.list; sp; sp = sp->next) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008544 setvar0(n->nfor.var, sp->text);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008545 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008546 if (evalskip) {
8547 if (evalskip == SKIPCONT && --skipcount <= 0) {
8548 evalskip = 0;
8549 continue;
8550 }
8551 if (evalskip == SKIPBREAK && --skipcount <= 0)
8552 evalskip = 0;
8553 break;
8554 }
8555 }
8556 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008557 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008558 popstackmark(&smark);
8559}
8560
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008561static void
Eric Andersenc470f442003-07-28 09:56:35 +00008562evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008563{
8564 union node *cp;
8565 union node *patp;
8566 struct arglist arglist;
8567 struct stackmark smark;
8568
8569 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008570 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008571 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008572 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008573 exitstatus = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008574 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8575 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008576 if (casematch(patp, arglist.list->text)) {
8577 if (evalskip == 0) {
8578 evaltree(cp->nclist.body, flags);
8579 }
8580 goto out;
8581 }
8582 }
8583 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008584 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008585 popstackmark(&smark);
8586}
8587
Eric Andersenc470f442003-07-28 09:56:35 +00008588/*
8589 * Kick off a subshell to evaluate a tree.
8590 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008591static void
Eric Andersenc470f442003-07-28 09:56:35 +00008592evalsubshell(union node *n, int flags)
8593{
8594 struct job *jp;
8595 int backgnd = (n->type == NBACKGND);
8596 int status;
8597
8598 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008599 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008600 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008601 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008602 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008603 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008604 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008605 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008606 flags |= EV_EXIT;
8607 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008608 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008609 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008610 redirect(n->nredir.redirect, 0);
8611 evaltreenr(n->nredir.n, flags);
8612 /* never returns */
8613 }
8614 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008615 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008616 status = waitforjob(jp);
8617 exitstatus = status;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008618 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008619}
8620
Eric Andersenc470f442003-07-28 09:56:35 +00008621/*
8622 * Compute the names of the files in a redirection list.
8623 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008624static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008625static void
8626expredir(union node *n)
8627{
8628 union node *redir;
8629
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008630 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008631 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008632
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008633 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008634 fn.lastp = &fn.list;
8635 switch (redir->type) {
8636 case NFROMTO:
8637 case NFROM:
8638 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008639#if ENABLE_ASH_BASH_COMPAT
8640 case NTO2:
8641#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008642 case NCLOBBER:
8643 case NAPPEND:
8644 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008645 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008646#if ENABLE_ASH_BASH_COMPAT
8647 store_expfname:
8648#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008649#if 0
8650// By the design of stack allocator, the loop of this kind:
8651// while true; do while true; do break; done </dev/null; done
8652// will look like a memory leak: ash plans to free expfname's
8653// of "/dev/null" as soon as it finishes running the loop
8654// (in this case, never).
8655// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008656 if (redir->nfile.expfname)
8657 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008658// It results in corrupted state of stacked allocations.
8659#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008660 redir->nfile.expfname = fn.list->text;
8661 break;
8662 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008663 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008664 if (redir->ndup.vname) {
8665 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008666 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008667 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008668#if ENABLE_ASH_BASH_COMPAT
8669//FIXME: we used expandarg with different args!
8670 if (!isdigit_str9(fn.list->text)) {
8671 /* >&file, not >&fd */
8672 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8673 ash_msg_and_raise_error("redir error");
8674 redir->type = NTO2;
8675 goto store_expfname;
8676 }
8677#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008678 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008679 }
8680 break;
8681 }
8682 }
8683}
8684
Eric Andersencb57d552001-06-28 07:25:16 +00008685/*
Eric Andersencb57d552001-06-28 07:25:16 +00008686 * Evaluate a pipeline. All the processes in the pipeline are children
8687 * of the process creating the pipeline. (This differs from some versions
8688 * of the shell, which make the last process in a pipeline the parent
8689 * of all the rest.)
8690 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008691static void
Eric Andersenc470f442003-07-28 09:56:35 +00008692evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008693{
8694 struct job *jp;
8695 struct nodelist *lp;
8696 int pipelen;
8697 int prevfd;
8698 int pip[2];
8699
Eric Andersenc470f442003-07-28 09:56:35 +00008700 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008701 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008702 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008703 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008704 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008705 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008706 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008707 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008708 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008709 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008710 pip[1] = -1;
8711 if (lp->next) {
8712 if (pipe(pip) < 0) {
8713 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008714 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008715 }
8716 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008717 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008718 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008719 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008720 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008721 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008722 if (prevfd > 0) {
8723 dup2(prevfd, 0);
8724 close(prevfd);
8725 }
8726 if (pip[1] > 1) {
8727 dup2(pip[1], 1);
8728 close(pip[1]);
8729 }
Eric Andersenc470f442003-07-28 09:56:35 +00008730 evaltreenr(lp->n, flags);
8731 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008732 }
8733 if (prevfd >= 0)
8734 close(prevfd);
8735 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008736 /* Don't want to trigger debugging */
8737 if (pip[1] != -1)
8738 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008739 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008740 if (n->npipe.pipe_backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008741 exitstatus = waitforjob(jp);
8742 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00008743 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008744 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008745}
8746
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008747/*
8748 * Controls whether the shell is interactive or not.
8749 */
8750static void
8751setinteractive(int on)
8752{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008753 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008754
8755 if (++on == is_interactive)
8756 return;
8757 is_interactive = on;
8758 setsignal(SIGINT);
8759 setsignal(SIGQUIT);
8760 setsignal(SIGTERM);
8761#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8762 if (is_interactive > 1) {
8763 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008764 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008765
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008766 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008767 /* note: ash and hush share this string */
8768 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008769 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8770 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008771 bb_banner,
8772 "built-in shell (ash)"
8773 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008774 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008775 }
8776 }
8777#endif
8778}
8779
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008780static void
8781optschanged(void)
8782{
8783#if DEBUG
8784 opentrace();
8785#endif
8786 setinteractive(iflag);
8787 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008788#if ENABLE_FEATURE_EDITING_VI
8789 if (viflag)
8790 line_input_state->flags |= VI_MODE;
8791 else
8792 line_input_state->flags &= ~VI_MODE;
8793#else
8794 viflag = 0; /* forcibly keep the option off */
8795#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008796}
8797
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008798static struct localvar *localvars;
8799
8800/*
8801 * Called after a function returns.
8802 * Interrupts must be off.
8803 */
8804static void
8805poplocalvars(void)
8806{
8807 struct localvar *lvp;
8808 struct var *vp;
8809
8810 while ((lvp = localvars) != NULL) {
8811 localvars = lvp->next;
8812 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008813 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008814 if (vp == NULL) { /* $- saved */
8815 memcpy(optlist, lvp->text, sizeof(optlist));
8816 free((char*)lvp->text);
8817 optschanged();
8818 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008819 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008820 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008821 if (vp->var_func)
8822 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008823 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008824 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008825 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008826 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008827 }
8828 free(lvp);
8829 }
8830}
8831
8832static int
8833evalfun(struct funcnode *func, int argc, char **argv, int flags)
8834{
8835 volatile struct shparam saveparam;
8836 struct localvar *volatile savelocalvars;
8837 struct jmploc *volatile savehandler;
8838 struct jmploc jmploc;
8839 int e;
8840
8841 saveparam = shellparam;
8842 savelocalvars = localvars;
8843 e = setjmp(jmploc.loc);
8844 if (e) {
8845 goto funcdone;
8846 }
8847 INT_OFF;
8848 savehandler = exception_handler;
8849 exception_handler = &jmploc;
8850 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008851 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008852 func->count++;
8853 funcnest++;
8854 INT_ON;
8855 shellparam.nparam = argc - 1;
8856 shellparam.p = argv + 1;
8857#if ENABLE_ASH_GETOPTS
8858 shellparam.optind = 1;
8859 shellparam.optoff = -1;
8860#endif
8861 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008862 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008863 INT_OFF;
8864 funcnest--;
8865 freefunc(func);
8866 poplocalvars();
8867 localvars = savelocalvars;
8868 freeparam(&shellparam);
8869 shellparam = saveparam;
8870 exception_handler = savehandler;
8871 INT_ON;
8872 evalskip &= ~SKIPFUNC;
8873 return e;
8874}
8875
Denis Vlasenko131ae172007-02-18 13:00:19 +00008876#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008877static char **
8878parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008879{
8880 char *cp, c;
8881
8882 for (;;) {
8883 cp = *++argv;
8884 if (!cp)
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008885 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008886 if (*cp++ != '-')
8887 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008888 c = *cp++;
8889 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008890 break;
8891 if (c == '-' && !*cp) {
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008892 if (!*++argv)
8893 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008894 break;
8895 }
8896 do {
8897 switch (c) {
8898 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00008899 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00008900 break;
8901 default:
8902 /* run 'typecmd' for other options */
Denys Vlasenkoe2f32c02015-10-29 19:46:40 +01008903 return NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008904 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00008905 c = *cp++;
8906 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00008907 }
8908 return argv;
8909}
8910#endif
8911
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008912/*
8913 * Make a variable a local variable. When a variable is made local, it's
8914 * value and flags are saved in a localvar structure. The saved values
8915 * will be restored when the shell function returns. We handle the name
Denys Vlasenkoe0a4e102015-05-13 02:20:14 +02008916 * "-" as a special case: it makes changes to "set +-options" local
8917 * (options will be restored on return from the function).
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008918 */
8919static void
8920mklocal(char *name)
8921{
8922 struct localvar *lvp;
8923 struct var **vpp;
8924 struct var *vp;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008925 char *eq = strchr(name, '=');
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008926
8927 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008928 /* Cater for duplicate "local". Examples:
8929 * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x
8930 * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x
8931 */
8932 lvp = localvars;
8933 while (lvp) {
Eugene Rudoy1285aa62015-04-26 23:32:00 +02008934 if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008935 if (eq)
8936 setvareq(name, 0);
8937 /* else:
8938 * it's a duplicate "local VAR" declaration, do nothing
8939 */
8940 return;
8941 }
8942 lvp = lvp->next;
8943 }
8944
8945 lvp = ckzalloc(sizeof(*lvp));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008946 if (LONE_DASH(name)) {
8947 char *p;
8948 p = ckmalloc(sizeof(optlist));
8949 lvp->text = memcpy(p, optlist, sizeof(optlist));
8950 vp = NULL;
8951 } else {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008952 vpp = hashvar(name);
8953 vp = *findvar(vpp, name);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008954 if (vp == NULL) {
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008955 /* variable did not exist yet */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008956 if (eq)
8957 setvareq(name, VSTRFIXED);
8958 else
8959 setvar(name, NULL, VSTRFIXED);
8960 vp = *vpp; /* the new variable */
8961 lvp->flags = VUNSET;
8962 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008963 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008964 lvp->flags = vp->flags;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008965 /* make sure neither "struct var" nor string gets freed
8966 * during (un)setting:
8967 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008968 vp->flags |= VSTRFIXED|VTEXTFIXED;
8969 if (eq)
8970 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01008971 else
8972 /* "local VAR" unsets VAR: */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02008973 setvar0(name, NULL);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008974 }
8975 }
8976 lvp->vp = vp;
8977 lvp->next = localvars;
8978 localvars = lvp;
8979 INT_ON;
8980}
8981
8982/*
8983 * The "local" command.
8984 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02008985static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00008986localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008987{
8988 char *name;
8989
Ron Yorstonef2386b2015-10-29 16:19:14 +00008990 if (!funcnest)
8991 ash_msg_and_raise_error("not in a function");
8992
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008993 argv = argptr;
8994 while ((name = *argv++) != NULL) {
8995 mklocal(name);
8996 }
8997 return 0;
8998}
8999
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009000static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009001falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009002{
9003 return 1;
9004}
9005
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009006static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009007truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009008{
9009 return 0;
9010}
9011
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009012static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009013execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009014{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009015 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009016 iflag = 0; /* exit on error */
9017 mflag = 0;
9018 optschanged();
9019 shellexec(argv + 1, pathval(), 0);
9020 }
9021 return 0;
9022}
9023
9024/*
9025 * The return command.
9026 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009027static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009028returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009029{
9030 /*
9031 * If called outside a function, do what ksh does;
9032 * skip the rest of the file.
9033 */
9034 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9035 return argv[1] ? number(argv[1]) : exitstatus;
9036}
9037
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009038/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009039static int breakcmd(int, char **) FAST_FUNC;
9040static int dotcmd(int, char **) FAST_FUNC;
9041static int evalcmd(int, char **) FAST_FUNC;
9042static int exitcmd(int, char **) FAST_FUNC;
9043static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009044#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009045static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009046#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009047#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009048static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009049#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009050#if MAX_HISTORY
9051static int historycmd(int, char **) FAST_FUNC;
9052#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009053#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009054static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009055#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009056static int readcmd(int, char **) FAST_FUNC;
9057static int setcmd(int, char **) FAST_FUNC;
9058static int shiftcmd(int, char **) FAST_FUNC;
9059static int timescmd(int, char **) FAST_FUNC;
9060static int trapcmd(int, char **) FAST_FUNC;
9061static int umaskcmd(int, char **) FAST_FUNC;
9062static int unsetcmd(int, char **) FAST_FUNC;
9063static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009064
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009065#define BUILTIN_NOSPEC "0"
9066#define BUILTIN_SPECIAL "1"
9067#define BUILTIN_REGULAR "2"
9068#define BUILTIN_SPEC_REG "3"
9069#define BUILTIN_ASSIGN "4"
9070#define BUILTIN_SPEC_ASSG "5"
9071#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009072#define BUILTIN_SPEC_REG_ASSG "7"
9073
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009074/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009075#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009076static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009077#endif
9078#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009079static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009080#endif
9081#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009082static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009083#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009084
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009085/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009086static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009087 { BUILTIN_SPEC_REG "." , dotcmd },
9088 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009089#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009090 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009091#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009092 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009093#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009094#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009095#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009096 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009097#endif
9098#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009099 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009100#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009101 { BUILTIN_SPEC_REG "break" , breakcmd },
9102 { BUILTIN_REGULAR "cd" , cdcmd },
9103 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009104#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009105 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009106#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009107 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009108#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009109 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009110#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009111 { BUILTIN_SPEC_REG "eval" , evalcmd },
9112 { BUILTIN_SPEC_REG "exec" , execcmd },
9113 { BUILTIN_SPEC_REG "exit" , exitcmd },
9114 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9115 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009116#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009117 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009118#endif
9119#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009120 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009121#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009122 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009123#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009124 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009125#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009126#if MAX_HISTORY
9127 { BUILTIN_NOSPEC "history" , historycmd },
9128#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009129#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009130 { BUILTIN_REGULAR "jobs" , jobscmd },
9131 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009132#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009133#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009134 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009135#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009136 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009137#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009138 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009139#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009140 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9141 { BUILTIN_REGULAR "read" , readcmd },
9142 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9143 { BUILTIN_SPEC_REG "return" , returncmd },
9144 { BUILTIN_SPEC_REG "set" , setcmd },
9145 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009146#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009147 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009148#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009149#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009150 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009151#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009152 { BUILTIN_SPEC_REG "times" , timescmd },
9153 { BUILTIN_SPEC_REG "trap" , trapcmd },
9154 { BUILTIN_REGULAR "true" , truecmd },
9155 { BUILTIN_NOSPEC "type" , typecmd },
9156 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9157 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009158#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009159 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009160#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009161 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9162 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009163};
9164
Denis Vlasenko80591b02008-03-25 07:49:43 +00009165/* Should match the above table! */
9166#define COMMANDCMD (builtintab + \
9167 2 + \
9168 1 * ENABLE_ASH_BUILTIN_TEST + \
9169 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9170 1 * ENABLE_ASH_ALIAS + \
9171 1 * ENABLE_ASH_JOB_CONTROL + \
9172 3)
9173#define EXECCMD (builtintab + \
9174 2 + \
9175 1 * ENABLE_ASH_BUILTIN_TEST + \
9176 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9177 1 * ENABLE_ASH_ALIAS + \
9178 1 * ENABLE_ASH_JOB_CONTROL + \
9179 3 + \
9180 1 * ENABLE_ASH_CMDCMD + \
9181 1 + \
9182 ENABLE_ASH_BUILTIN_ECHO + \
9183 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009184
9185/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009186 * Search the table of builtin commands.
9187 */
9188static struct builtincmd *
9189find_builtin(const char *name)
9190{
9191 struct builtincmd *bp;
9192
9193 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009194 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009195 pstrcmp
9196 );
9197 return bp;
9198}
9199
9200/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009201 * Execute a simple command.
9202 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009203static int
9204isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009205{
9206 const char *q = endofname(p);
9207 if (p == q)
9208 return 0;
9209 return *q == '=';
9210}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009211static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009212bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009213{
9214 /* Preserve exitstatus of a previous possible redirection
9215 * as POSIX mandates */
9216 return back_exitstatus;
9217}
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02009218static void
Eric Andersenc470f442003-07-28 09:56:35 +00009219evalcommand(union node *cmd, int flags)
9220{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009221 static const struct builtincmd null_bltin = {
9222 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009223 };
Eric Andersenc470f442003-07-28 09:56:35 +00009224 struct stackmark smark;
9225 union node *argp;
9226 struct arglist arglist;
9227 struct arglist varlist;
9228 char **argv;
9229 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009230 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009231 struct cmdentry cmdentry;
9232 struct job *jp;
9233 char *lastarg;
9234 const char *path;
9235 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009236 int status;
9237 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009238 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009239 smallint cmd_is_exec;
9240 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009241
9242 /* First expand the arguments. */
9243 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9244 setstackmark(&smark);
9245 back_exitstatus = 0;
9246
9247 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009248 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009249 varlist.lastp = &varlist.list;
9250 *varlist.lastp = NULL;
9251 arglist.lastp = &arglist.list;
9252 *arglist.lastp = NULL;
9253
9254 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009255 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009256 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9257 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9258 }
9259
Eric Andersenc470f442003-07-28 09:56:35 +00009260 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9261 struct strlist **spp;
9262
9263 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009264 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009265 expandarg(argp, &arglist, EXP_VARTILDE);
9266 else
9267 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9268
Eric Andersenc470f442003-07-28 09:56:35 +00009269 for (sp = *spp; sp; sp = sp->next)
9270 argc++;
9271 }
9272
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009273 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009274 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009275 TRACE(("evalcommand arg: %s\n", sp->text));
9276 *nargv++ = sp->text;
9277 }
9278 *nargv = NULL;
9279
9280 lastarg = NULL;
9281 if (iflag && funcnest == 0 && argc > 0)
9282 lastarg = nargv[-1];
9283
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009284 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009285 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009286 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009287
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009288 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009289 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9290 struct strlist **spp;
9291 char *p;
9292
9293 spp = varlist.lastp;
9294 expandarg(argp, &varlist, EXP_VARTILDE);
9295
9296 /*
9297 * Modify the command lookup path, if a PATH= assignment
9298 * is present
9299 */
9300 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009301 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009302 path = p;
9303 }
9304
9305 /* Print the command if xflag is set. */
9306 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009307 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009308 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009309
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009310 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009311 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009312 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009313 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009314 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009315 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009316 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009317 }
9318 sp = arglist.list;
9319 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009320 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009321 }
9322
9323 cmd_is_exec = 0;
9324 spclbltin = -1;
9325
9326 /* Now locate the command. */
9327 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009328 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009329#if ENABLE_ASH_CMDCMD
9330 const char *oldpath = path + 5;
9331#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009332 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009333 for (;;) {
9334 find_command(argv[0], &cmdentry, cmd_flag, path);
9335 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009336 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009337 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009338 goto bail;
9339 }
9340
9341 /* implement bltin and command here */
9342 if (cmdentry.cmdtype != CMDBUILTIN)
9343 break;
9344 if (spclbltin < 0)
9345 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9346 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009347 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009348#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009349 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009350 path = oldpath;
9351 nargv = parse_command_args(argv, &path);
9352 if (!nargv)
9353 break;
9354 argc -= nargv - argv;
9355 argv = nargv;
9356 cmd_flag |= DO_NOFUNC;
9357 } else
9358#endif
9359 break;
9360 }
9361 }
9362
9363 if (status) {
9364 /* We have a redirection error. */
9365 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009366 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009367 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009368 exitstatus = status;
9369 goto out;
9370 }
9371
9372 /* Execute the command. */
9373 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009374 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009375
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009376#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009377/* (1) BUG: if variables are set, we need to fork, or save/restore them
9378 * around run_nofork_applet() call.
9379 * (2) Should this check also be done in forkshell()?
9380 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9381 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009382 /* find_command() encodes applet_no as (-2 - applet_no) */
9383 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009384 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009385 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009386 /* run <applet>_main() */
9387 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009388 break;
9389 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009390#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009391 /* Can we avoid forking off? For example, very last command
9392 * in a script or a subshell does not need forking,
9393 * we can just exec it.
9394 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009395 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009396 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009397 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009398 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009399 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009400 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009401 exitstatus = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009402 INT_ON;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009403 TRACE(("forked child exited with %d\n", exitstatus));
Eric Andersenc470f442003-07-28 09:56:35 +00009404 break;
9405 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009406 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009407 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009408 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009409 }
9410 listsetvar(varlist.list, VEXPORT|VSTACK);
9411 shellexec(argv, path, cmdentry.u.index);
9412 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009413 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009414 case CMDBUILTIN:
9415 cmdenviron = varlist.list;
9416 if (cmdenviron) {
9417 struct strlist *list = cmdenviron;
9418 int i = VNOSET;
9419 if (spclbltin > 0 || argc == 0) {
9420 i = 0;
9421 if (cmd_is_exec && argc > 1)
9422 i = VEXPORT;
9423 }
9424 listsetvar(list, i);
9425 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009426 /* Tight loop with builtins only:
9427 * "while kill -0 $child; do true; done"
9428 * will never exit even if $child died, unless we do this
9429 * to reap the zombie and make kill detect that it's gone: */
9430 dowait(DOWAIT_NONBLOCK, NULL);
9431
Eric Andersenc470f442003-07-28 09:56:35 +00009432 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9433 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009434 int i = exception_type;
Eric Andersenc470f442003-07-28 09:56:35 +00009435 if (i == EXEXIT)
9436 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009437 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009438 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009439 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009440 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009441 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009442 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009443 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009444 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009445 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009446 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009447 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009448 }
9449 break;
9450
9451 case CMDFUNCTION:
9452 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009453 /* See above for the rationale */
9454 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009455 if (evalfun(cmdentry.u.func, argc, argv, flags))
9456 goto raise;
9457 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009458 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009459
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009460 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009461 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009462 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009463 /* dsl: I think this is intended to be used to support
9464 * '_' in 'vi' command mode during line editing...
9465 * However I implemented that within libedit itself.
9466 */
Denys Vlasenko0a0acb52015-04-18 19:36:38 +02009467 setvar0("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009468 }
Eric Andersenc470f442003-07-28 09:56:35 +00009469 popstackmark(&smark);
9470}
9471
9472static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009473evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9474{
Eric Andersenc470f442003-07-28 09:56:35 +00009475 char *volatile savecmdname;
9476 struct jmploc *volatile savehandler;
9477 struct jmploc jmploc;
9478 int i;
9479
9480 savecmdname = commandname;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009481 i = setjmp(jmploc.loc);
9482 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009483 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009484 savehandler = exception_handler;
9485 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009486 commandname = argv[0];
9487 argptr = argv + 1;
9488 optptr = NULL; /* initialize nextopt */
9489 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009490 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009491 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009492 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009493 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009494 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009495 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009496
9497 return i;
9498}
9499
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009500static int
9501goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009502{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009503 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009504}
9505
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009506
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009507/*
9508 * Search for a command. This is called before we fork so that the
9509 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009510 * the child. The check for "goodname" is an overly conservative
9511 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009512 */
Eric Andersenc470f442003-07-28 09:56:35 +00009513static void
9514prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009515{
9516 struct cmdentry entry;
9517
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009518 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9519 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009520}
9521
Eric Andersencb57d552001-06-28 07:25:16 +00009522
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009523/* ============ Builtin commands
9524 *
9525 * Builtin commands whose functions are closely tied to evaluation
9526 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009527 */
9528
9529/*
Eric Andersencb57d552001-06-28 07:25:16 +00009530 * Handle break and continue commands. Break, continue, and return are
9531 * all handled by setting the evalskip flag. The evaluation routines
9532 * above all check this flag, and if it is set they start skipping
9533 * commands rather than executing them. The variable skipcount is
9534 * the number of loops to break/continue, or the number of function
9535 * levels to return. (The latter is always 1.) It should probably
9536 * be an error to break out of more loops than exist, but it isn't
9537 * in the standard shell so we don't make it one here.
9538 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009539static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009540breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009541{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009542 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009543
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009544 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009545 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009546 if (n > loopnest)
9547 n = loopnest;
9548 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009549 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009550 skipcount = n;
9551 }
9552 return 0;
9553}
9554
Eric Andersenc470f442003-07-28 09:56:35 +00009555
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009556/* ============ input.c
9557 *
Eric Andersen90898442003-08-06 11:20:52 +00009558 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009559 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009560
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009561enum {
9562 INPUT_PUSH_FILE = 1,
9563 INPUT_NOFILE_OK = 2,
9564};
Eric Andersencb57d552001-06-28 07:25:16 +00009565
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009566static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009567/* values of checkkwd variable */
9568#define CHKALIAS 0x1
9569#define CHKKWD 0x2
9570#define CHKNL 0x4
9571
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009572/*
9573 * Push a string back onto the input at this current parsefile level.
9574 * We handle aliases this way.
9575 */
9576#if !ENABLE_ASH_ALIAS
9577#define pushstring(s, ap) pushstring(s)
9578#endif
9579static void
9580pushstring(char *s, struct alias *ap)
9581{
9582 struct strpush *sp;
9583 int len;
9584
9585 len = strlen(s);
9586 INT_OFF;
9587 if (g_parsefile->strpush) {
9588 sp = ckzalloc(sizeof(*sp));
9589 sp->prev = g_parsefile->strpush;
9590 } else {
9591 sp = &(g_parsefile->basestrpush);
9592 }
9593 g_parsefile->strpush = sp;
9594 sp->prev_string = g_parsefile->next_to_pgetc;
9595 sp->prev_left_in_line = g_parsefile->left_in_line;
9596#if ENABLE_ASH_ALIAS
9597 sp->ap = ap;
9598 if (ap) {
9599 ap->flag |= ALIASINUSE;
9600 sp->string = s;
9601 }
9602#endif
9603 g_parsefile->next_to_pgetc = s;
9604 g_parsefile->left_in_line = len;
9605 INT_ON;
9606}
9607
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009608static void
9609popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009610{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009611 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009612
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009613 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009614#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009615 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009616 if (g_parsefile->next_to_pgetc[-1] == ' '
9617 || g_parsefile->next_to_pgetc[-1] == '\t'
9618 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009619 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009620 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009621 if (sp->string != sp->ap->val) {
9622 free(sp->string);
9623 }
9624 sp->ap->flag &= ~ALIASINUSE;
9625 if (sp->ap->flag & ALIASDEAD) {
9626 unalias(sp->ap->name);
9627 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009628 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009629#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009630 g_parsefile->next_to_pgetc = sp->prev_string;
9631 g_parsefile->left_in_line = sp->prev_left_in_line;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009632 g_parsefile->strpush = sp->prev;
9633 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009634 free(sp);
9635 INT_ON;
9636}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009637
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009638//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9639//it peeks whether it is &>, and then pushes back both chars.
9640//This function needs to save last *next_to_pgetc to buf[0]
9641//to make two pungetc() reliable. Currently,
9642// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009643static int
9644preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009645{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009646 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009647 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009648
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009649 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009650#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009651 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009652 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Ron Yorston61d6ae22015-04-19 10:50:25 +01009653 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009654 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009655 int timeout = -1;
9656# if ENABLE_ASH_IDLE_TIMEOUT
9657 if (iflag) {
9658 const char *tmout_var = lookupvar("TMOUT");
9659 if (tmout_var) {
9660 timeout = atoi(tmout_var) * 1000;
9661 if (timeout <= 0)
9662 timeout = -1;
9663 }
9664 }
9665# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009666# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009667 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009668# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009669 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009670 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009671 if (nr == 0) {
9672 /* Ctrl+C pressed */
9673 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009674 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009675 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009676 raise(SIGINT);
9677 return 1;
9678 }
Eric Andersenc470f442003-07-28 09:56:35 +00009679 goto retry;
9680 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009681 if (nr < 0) {
9682 if (errno == 0) {
9683 /* Ctrl+D pressed */
9684 nr = 0;
9685 }
9686# if ENABLE_ASH_IDLE_TIMEOUT
9687 else if (errno == EAGAIN && timeout > 0) {
Denys Vlasenkod60752f2015-10-07 22:42:45 +02009688 puts("\007timed out waiting for input: auto-logout");
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009689 exitshell();
9690 }
9691# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009692 }
Eric Andersencb57d552001-06-28 07:25:16 +00009693 }
9694#else
Ron Yorston61d6ae22015-04-19 10:50:25 +01009695 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009696#endif
9697
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009698#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009699 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009700 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009701 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009702 if (flags >= 0 && (flags & O_NONBLOCK)) {
9703 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009704 if (fcntl(0, F_SETFL, flags) >= 0) {
9705 out2str("sh: turning off NDELAY mode\n");
9706 goto retry;
9707 }
9708 }
9709 }
9710 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009711#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009712 return nr;
9713}
9714
9715/*
9716 * Refill the input buffer and return the next input character:
9717 *
9718 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009719 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9720 * or we are reading from a string so we can't refill the buffer,
9721 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009722 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009723 * 4) Process input up to the next newline, deleting nul characters.
9724 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009725//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9726#define pgetc_debug(...) ((void)0)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009727static int
Eric Andersenc470f442003-07-28 09:56:35 +00009728preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009729{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009730 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009731 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009732
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009733 while (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009734#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009735 if (g_parsefile->left_in_line == -1
9736 && g_parsefile->strpush->ap
9737 && g_parsefile->next_to_pgetc[-1] != ' '
9738 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009739 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009740 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009741 return PEOA;
9742 }
Eric Andersen2870d962001-07-02 17:27:21 +00009743#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009744 popstring();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009745 /* try "pgetc" now: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009746 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9747 g_parsefile->left_in_line,
9748 g_parsefile->next_to_pgetc,
9749 g_parsefile->next_to_pgetc);
9750 if (--g_parsefile->left_in_line >= 0)
9751 return (unsigned char)(*g_parsefile->next_to_pgetc++);
Eric Andersencb57d552001-06-28 07:25:16 +00009752 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009753 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009754 * "pgetc" needs refilling.
9755 */
9756
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009757 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009758 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009759 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009760 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009761 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009762 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009763 /* even in failure keep left_in_line and next_to_pgetc
9764 * in lock step, for correct multi-layer pungetc.
9765 * left_in_line was decremented before preadbuffer(),
9766 * must inc next_to_pgetc: */
9767 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009768 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009769 }
Eric Andersencb57d552001-06-28 07:25:16 +00009770
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009771 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009772 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009773 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009774 again:
9775 more = preadfd();
9776 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009777 /* don't try reading again */
9778 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009779 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009780 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009781 return PEOF;
9782 }
9783 }
9784
Denis Vlasenko727752d2008-11-28 03:41:47 +00009785 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009786 * Set g_parsefile->left_in_line
9787 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009788 * NUL chars are deleted.
9789 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009790 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009791 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009792 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009793
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009794 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009795
Denis Vlasenko727752d2008-11-28 03:41:47 +00009796 c = *q;
9797 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009798 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009799 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009800 q++;
9801 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009802 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009803 break;
9804 }
Eric Andersencb57d552001-06-28 07:25:16 +00009805 }
9806
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009807 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009808 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9809 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009810 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009811 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009812 }
9813 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009814 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009815
Eric Andersencb57d552001-06-28 07:25:16 +00009816 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009817 char save = *q;
9818 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009819 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009820 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009821 }
9822
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009823 pgetc_debug("preadbuffer at %d:%p'%s'",
9824 g_parsefile->left_in_line,
9825 g_parsefile->next_to_pgetc,
9826 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009827 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009828}
9829
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009830#define pgetc_as_macro() \
9831 (--g_parsefile->left_in_line >= 0 \
Denys Vlasenkocd716832009-11-28 22:14:02 +01009832 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009833 : preadbuffer() \
9834 )
Denis Vlasenko727752d2008-11-28 03:41:47 +00009835
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009836static int
9837pgetc(void)
9838{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009839 pgetc_debug("pgetc_fast at %d:%p'%s'",
9840 g_parsefile->left_in_line,
9841 g_parsefile->next_to_pgetc,
9842 g_parsefile->next_to_pgetc);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009843 return pgetc_as_macro();
9844}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009845
9846#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009847# define pgetc_fast() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009848#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009849# define pgetc_fast() pgetc_as_macro()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009850#endif
9851
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009852#if ENABLE_ASH_ALIAS
9853static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009854pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009855{
9856 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009857 do {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009858 pgetc_debug("pgetc_fast at %d:%p'%s'",
9859 g_parsefile->left_in_line,
9860 g_parsefile->next_to_pgetc,
9861 g_parsefile->next_to_pgetc);
Denis Vlasenko834dee72008-10-07 09:18:30 +00009862 c = pgetc_fast();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009863 } while (c == PEOA);
9864 return c;
9865}
9866#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009867# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009868#endif
9869
9870/*
9871 * Read a line from the script.
9872 */
9873static char *
9874pfgets(char *line, int len)
9875{
9876 char *p = line;
9877 int nleft = len;
9878 int c;
9879
9880 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009881 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009882 if (c == PEOF) {
9883 if (p == line)
9884 return NULL;
9885 break;
9886 }
9887 *p++ = c;
9888 if (c == '\n')
9889 break;
9890 }
9891 *p = '\0';
9892 return line;
9893}
9894
Eric Andersenc470f442003-07-28 09:56:35 +00009895/*
9896 * Undo the last call to pgetc. Only one character may be pushed back.
9897 * PEOF may be pushed back.
9898 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009899static void
Eric Andersenc470f442003-07-28 09:56:35 +00009900pungetc(void)
9901{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009902 g_parsefile->left_in_line++;
9903 g_parsefile->next_to_pgetc--;
9904 pgetc_debug("pushed back to %d:%p'%s'",
9905 g_parsefile->left_in_line,
9906 g_parsefile->next_to_pgetc,
9907 g_parsefile->next_to_pgetc);
Eric Andersencb57d552001-06-28 07:25:16 +00009908}
9909
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009910/*
9911 * To handle the "." command, a stack of input files is used. Pushfile
9912 * adds a new entry to the stack and popfile restores the previous level.
9913 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009914static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009915pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009916{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009917 struct parsefile *pf;
9918
Denis Vlasenko597906c2008-02-20 16:38:54 +00009919 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009920 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009921 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +00009922 /*pf->strpush = NULL; - ckzalloc did it */
9923 /*pf->basestrpush.prev = NULL;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009924 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009925}
9926
9927static void
9928popfile(void)
9929{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009930 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +00009931
Denis Vlasenkob012b102007-02-19 22:43:01 +00009932 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009933 if (pf->pf_fd >= 0)
9934 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +00009935 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009936 while (pf->strpush)
9937 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009938 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009939 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009940 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009941}
9942
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009943/*
9944 * Return to top level.
9945 */
9946static void
9947popallfiles(void)
9948{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009949 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009950 popfile();
9951}
9952
9953/*
9954 * Close the file(s) that the shell is reading commands from. Called
9955 * after a fork is done.
9956 */
9957static void
9958closescript(void)
9959{
9960 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009961 if (g_parsefile->pf_fd > 0) {
9962 close(g_parsefile->pf_fd);
9963 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009964 }
9965}
9966
9967/*
9968 * Like setinputfile, but takes an open file descriptor. Call this with
9969 * interrupts off.
9970 */
9971static void
9972setinputfd(int fd, int push)
9973{
Denis Vlasenko96e1b382007-09-30 23:50:48 +00009974 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009975 if (push) {
9976 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009977 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009978 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009979 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009980 if (g_parsefile->buf == NULL)
9981 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009982 g_parsefile->left_in_buffer = 0;
9983 g_parsefile->left_in_line = 0;
9984 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009985}
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009986
Eric Andersenc470f442003-07-28 09:56:35 +00009987/*
9988 * Set the input to take input from a file. If push is set, push the
9989 * old input onto the stack first.
9990 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009991static int
9992setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +00009993{
9994 int fd;
9995 int fd2;
9996
Denis Vlasenkob012b102007-02-19 22:43:01 +00009997 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009998 fd = open(fname, O_RDONLY);
9999 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010000 if (flags & INPUT_NOFILE_OK)
10001 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010002 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010003 }
Eric Andersenc470f442003-07-28 09:56:35 +000010004 if (fd < 10) {
10005 fd2 = copyfd(fd, 10);
10006 close(fd);
10007 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010008 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010009 fd = fd2;
10010 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010011 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010012 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010013 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010014 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010015}
10016
Eric Andersencb57d552001-06-28 07:25:16 +000010017/*
10018 * Like setinputfile, but takes input from a string.
10019 */
Eric Andersenc470f442003-07-28 09:56:35 +000010020static void
10021setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010022{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010023 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010024 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010025 g_parsefile->next_to_pgetc = string;
10026 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010027 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010028 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010029 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010030}
10031
10032
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010033/* ============ mail.c
10034 *
10035 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010036 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010037
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010038#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010039
Denys Vlasenko23841622015-10-09 15:52:03 +020010040/* Hash of mtimes of mailboxes */
10041static unsigned mailtime_hash;
Eric Andersenc470f442003-07-28 09:56:35 +000010042/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010043static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010044
Eric Andersencb57d552001-06-28 07:25:16 +000010045/*
Eric Andersenc470f442003-07-28 09:56:35 +000010046 * Print appropriate message(s) if mail has arrived.
10047 * If mail_var_path_changed is set,
10048 * then the value of MAIL has mail_var_path_changed,
10049 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010050 */
Eric Andersenc470f442003-07-28 09:56:35 +000010051static void
10052chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010053{
Eric Andersencb57d552001-06-28 07:25:16 +000010054 const char *mpath;
10055 char *p;
10056 char *q;
Denys Vlasenko23841622015-10-09 15:52:03 +020010057 unsigned new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010058 struct stackmark smark;
10059 struct stat statb;
10060
Eric Andersencb57d552001-06-28 07:25:16 +000010061 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010062 mpath = mpathset() ? mpathval() : mailval();
Denys Vlasenko23841622015-10-09 15:52:03 +020010063 new_hash = 0;
10064 for (;;) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010065 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010066 if (p == NULL)
10067 break;
10068 if (*p == '\0')
10069 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010070 for (q = p; *q; q++)
10071 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010072#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010073 if (q[-1] != '/')
10074 abort();
10075#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010076 q[-1] = '\0'; /* delete trailing '/' */
10077 if (stat(p, &statb) < 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010078 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010079 }
Denys Vlasenko23841622015-10-09 15:52:03 +020010080 /* Very simplistic "hash": just a sum of all mtimes */
10081 new_hash += (unsigned)statb.st_mtime;
10082 }
10083 if (!mail_var_path_changed && mailtime_hash != new_hash) {
Denys Vlasenko4cd99e72015-10-09 16:02:53 +020010084 if (mailtime_hash != 0)
10085 out2str("you have mail\n");
Denys Vlasenko23841622015-10-09 15:52:03 +020010086 mailtime_hash = new_hash;
Eric Andersencb57d552001-06-28 07:25:16 +000010087 }
Eric Andersenc470f442003-07-28 09:56:35 +000010088 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010089 popstackmark(&smark);
10090}
Eric Andersencb57d552001-06-28 07:25:16 +000010091
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010092static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010093changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010094{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010095 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010096}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010097
Denis Vlasenko131ae172007-02-18 13:00:19 +000010098#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010099
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010100
10101/* ============ ??? */
10102
Eric Andersencb57d552001-06-28 07:25:16 +000010103/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010104 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010105 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010106static void
10107setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010108{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010109 char **newparam;
10110 char **ap;
10111 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010112
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010113 for (nparam = 0; argv[nparam]; nparam++)
10114 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010115 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10116 while (*argv) {
10117 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010118 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010119 *ap = NULL;
10120 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010121 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010122 shellparam.nparam = nparam;
10123 shellparam.p = newparam;
10124#if ENABLE_ASH_GETOPTS
10125 shellparam.optind = 1;
10126 shellparam.optoff = -1;
10127#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010128}
10129
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010130/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010131 * Process shell options. The global variable argptr contains a pointer
10132 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010133 *
10134 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10135 * For a non-interactive shell, an error condition encountered
10136 * by a special built-in ... shall cause the shell to write a diagnostic message
10137 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010138 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010139 * ...
10140 * Utility syntax error (option or operand error) Shall exit
10141 * ...
10142 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10143 * we see that bash does not do that (set "finishes" with error code 1 instead,
10144 * and shell continues), and people rely on this behavior!
10145 * Testcase:
10146 * set -o barfoo 2>/dev/null
10147 * echo $?
10148 *
10149 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010150 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010151static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010152plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010153{
10154 int i;
10155
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010156 if (name) {
10157 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010158 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010159 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010160 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010161 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010162 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010163 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010164 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010165 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010166 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010167 if (val) {
10168 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10169 } else {
10170 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10171 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010172 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010173 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010174}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010175static void
10176setoption(int flag, int val)
10177{
10178 int i;
10179
10180 for (i = 0; i < NOPTS; i++) {
10181 if (optletters(i) == flag) {
10182 optlist[i] = val;
10183 return;
10184 }
10185 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010186 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010187 /* NOTREACHED */
10188}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010189static int
Eric Andersenc470f442003-07-28 09:56:35 +000010190options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010191{
10192 char *p;
10193 int val;
10194 int c;
10195
10196 if (cmdline)
10197 minusc = NULL;
10198 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010199 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010200 if (c != '-' && c != '+')
10201 break;
10202 argptr++;
10203 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010204 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010205 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010206 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010207 if (!cmdline) {
10208 /* "-" means turn off -x and -v */
10209 if (p[0] == '\0')
10210 xflag = vflag = 0;
10211 /* "--" means reset params */
10212 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010213 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010214 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010215 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010216 }
Eric Andersencb57d552001-06-28 07:25:16 +000010217 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010218 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010219 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010220 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010221 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010222 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010223 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010224 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010225 /* it already printed err message */
10226 return 1; /* error */
10227 }
Eric Andersencb57d552001-06-28 07:25:16 +000010228 if (*argptr)
10229 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010230 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10231 isloginsh = 1;
10232 /* bash does not accept +-login, we also won't */
10233 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010234 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010235 isloginsh = 1;
10236 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010237 } else {
10238 setoption(c, val);
10239 }
10240 }
10241 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010242 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010243}
10244
Eric Andersencb57d552001-06-28 07:25:16 +000010245/*
Eric Andersencb57d552001-06-28 07:25:16 +000010246 * The shift builtin command.
10247 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010248static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010249shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010250{
10251 int n;
10252 char **ap1, **ap2;
10253
10254 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010255 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010256 n = number(argv[1]);
10257 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010258 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010259 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010260 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010261 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010262 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010263 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010264 }
10265 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010266 while ((*ap2++ = *ap1++) != NULL)
10267 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010268#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010269 shellparam.optind = 1;
10270 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010271#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010272 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010273 return 0;
10274}
10275
Eric Andersencb57d552001-06-28 07:25:16 +000010276/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010277 * POSIX requires that 'set' (but not export or readonly) output the
10278 * variables in lexicographic order - by the locale's collating order (sigh).
10279 * Maybe we could keep them in an ordered balanced binary tree
10280 * instead of hashed lists.
10281 * For now just roll 'em through qsort for printing...
10282 */
10283static int
10284showvars(const char *sep_prefix, int on, int off)
10285{
10286 const char *sep;
10287 char **ep, **epend;
10288
10289 ep = listvars(on, off, &epend);
10290 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10291
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010292 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010293
10294 for (; ep < epend; ep++) {
10295 const char *p;
10296 const char *q;
10297
10298 p = strchrnul(*ep, '=');
10299 q = nullstr;
10300 if (*p)
10301 q = single_quote(++p);
10302 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10303 }
10304 return 0;
10305}
10306
10307/*
Eric Andersencb57d552001-06-28 07:25:16 +000010308 * The set command builtin.
10309 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010310static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010311setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010312{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010313 int retval;
10314
Denis Vlasenko68404f12008-03-17 09:00:54 +000010315 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010316 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010317
Denis Vlasenkob012b102007-02-19 22:43:01 +000010318 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010319 retval = options(/*cmdline:*/ 0);
10320 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010321 optschanged();
10322 if (*argptr != NULL) {
10323 setparam(argptr);
10324 }
Eric Andersencb57d552001-06-28 07:25:16 +000010325 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010326 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010327 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010328}
10329
Denis Vlasenko131ae172007-02-18 13:00:19 +000010330#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010331static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010332change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010333{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010334 uint32_t t;
10335
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010336 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010337 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010338 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010339 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010340 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010341 vrandom.flags &= ~VNOFUNC;
10342 } else {
10343 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010344 t = strtoul(value, NULL, 10);
10345 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010346 }
Eric Andersenef02f822004-03-11 13:34:24 +000010347}
Eric Andersen16767e22004-03-16 05:14:10 +000010348#endif
10349
Denis Vlasenko131ae172007-02-18 13:00:19 +000010350#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010351static int
Eric Andersenc470f442003-07-28 09:56:35 +000010352getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010353{
10354 char *p, *q;
10355 char c = '?';
10356 int done = 0;
10357 int err = 0;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010358 char sbuf[2];
Eric Andersena48b0a32003-10-22 10:56:47 +000010359 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010360
Denys Vlasenko9c541002015-10-07 15:44:36 +020010361 sbuf[1] = '\0';
10362
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010363 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010364 return 1;
10365 optnext = optfirst + *param_optind - 1;
10366
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010367 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010368 p = NULL;
10369 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010370 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010371 if (p == NULL || *p == '\0') {
10372 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010373 p = *optnext;
10374 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010375 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010376 p = NULL;
10377 done = 1;
10378 goto out;
10379 }
10380 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010381 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010382 goto atend;
10383 }
10384
10385 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010386 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010387 if (*q == '\0') {
10388 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010389 sbuf[0] = c;
10390 /*sbuf[1] = '\0'; - already is */
10391 err |= setvarsafe("OPTARG", sbuf, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010392 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010393 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010394 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010395 }
10396 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010397 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010398 }
10399 if (*++q == ':')
10400 q++;
10401 }
10402
10403 if (*++q == ':') {
10404 if (*p == '\0' && (p = *optnext) == NULL) {
10405 if (optstr[0] == ':') {
Denys Vlasenko9c541002015-10-07 15:44:36 +020010406 sbuf[0] = c;
10407 /*sbuf[1] = '\0'; - already is */
10408 err |= setvarsafe("OPTARG", sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010409 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010410 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010411 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010412 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010413 c = '?';
10414 }
Eric Andersenc470f442003-07-28 09:56:35 +000010415 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010416 }
10417
10418 if (p == *optnext)
10419 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010420 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010421 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010422 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010423 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010424 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010425 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010426 *param_optind = optnext - optfirst + 1;
Denys Vlasenko9c541002015-10-07 15:44:36 +020010427 err |= setvarsafe("OPTIND", itoa(*param_optind), VNOFUNC);
10428 sbuf[0] = c;
10429 /*sbuf[1] = '\0'; - already is */
10430 err |= setvarsafe(optvar, sbuf, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010431 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010432 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010433 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010434 flush_stdout_stderr();
10435 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010436 }
10437 return done;
10438}
Eric Andersenc470f442003-07-28 09:56:35 +000010439
10440/*
10441 * The getopts builtin. Shellparam.optnext points to the next argument
10442 * to be processed. Shellparam.optptr points to the next character to
10443 * be processed in the current argument. If shellparam.optnext is NULL,
10444 * then it's the first time getopts has been called.
10445 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010446static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010447getoptscmd(int argc, char **argv)
10448{
10449 char **optbase;
10450
10451 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010452 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010453 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010454 optbase = shellparam.p;
10455 if (shellparam.optind > shellparam.nparam + 1) {
10456 shellparam.optind = 1;
10457 shellparam.optoff = -1;
10458 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010459 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010460 optbase = &argv[3];
10461 if (shellparam.optind > argc - 2) {
10462 shellparam.optind = 1;
10463 shellparam.optoff = -1;
10464 }
10465 }
10466
10467 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010468 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010469}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010470#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010471
Eric Andersencb57d552001-06-28 07:25:16 +000010472
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010473/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010474
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010475struct heredoc {
10476 struct heredoc *next; /* next here document in list */
10477 union node *here; /* redirection node */
10478 char *eofmark; /* string indicating end of input */
10479 smallint striptabs; /* if set, strip leading tabs */
10480};
10481
10482static smallint tokpushback; /* last token pushed back */
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010483static smallint quoteflag; /* set if (part of) last token was quoted */
10484static token_id_t lasttoken; /* last token read (integer id Txxx) */
10485static struct heredoc *heredoclist; /* list of here documents to read */
10486static char *wordtext; /* text of last word returned by readtoken */
10487static struct nodelist *backquotelist;
10488static union node *redirnode;
10489static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010490
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010491static const char *
10492tokname(char *buf, int tok)
10493{
10494 if (tok < TSEMI)
10495 return tokname_array[tok] + 1;
10496 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10497 return buf;
10498}
10499
10500/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010501 * Called when an unexpected token is read during the parse. The argument
10502 * is the token that is expected, or -1 if more than one type of token can
10503 * occur at this point.
10504 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010505static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010506static void
10507raise_error_unexpected_syntax(int token)
10508{
10509 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010510 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010511 int l;
10512
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010513 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010514 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010515 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010516 raise_error_syntax(msg);
10517 /* NOTREACHED */
10518}
Eric Andersencb57d552001-06-28 07:25:16 +000010519
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010520#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010521
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010522/* parsing is heavily cross-recursive, need these forward decls */
10523static union node *andor(void);
10524static union node *pipeline(void);
10525static union node *parse_command(void);
10526static void parseheredoc(void);
Ron Yorstonc0e00762015-10-29 11:30:55 +000010527static int peektoken(void);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010528static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010529
Eric Andersenc470f442003-07-28 09:56:35 +000010530static union node *
10531list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010532{
10533 union node *n1, *n2, *n3;
10534 int tok;
10535
Eric Andersencb57d552001-06-28 07:25:16 +000010536 n1 = NULL;
10537 for (;;) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010538 switch (peektoken()) {
10539 case TNL:
10540 if (!(nlflag & 1))
10541 break;
10542 parseheredoc();
10543 return n1;
10544
10545 case TEOF:
10546 if (!n1 && (nlflag & 1))
10547 n1 = NODE_EOF;
10548 parseheredoc();
10549 return n1;
10550 }
10551
10552 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10553 if (nlflag == 2 && tokname_array[peektoken()][0])
10554 return n1;
10555 nlflag |= 2;
10556
Eric Andersencb57d552001-06-28 07:25:16 +000010557 n2 = andor();
10558 tok = readtoken();
10559 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010560 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010561 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010562 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010563 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010564 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010565 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010566 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010567 n2 = n3;
10568 }
10569 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010570 }
10571 }
10572 if (n1 == NULL) {
10573 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010574 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010575 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010576 n3->type = NSEMI;
10577 n3->nbinary.ch1 = n1;
10578 n3->nbinary.ch2 = n2;
10579 n1 = n3;
10580 }
10581 switch (tok) {
Ron Yorstonc0e00762015-10-29 11:30:55 +000010582 case TNL:
10583 case TEOF:
10584 tokpushback = 1;
10585 /* fall through */
Eric Andersencb57d552001-06-28 07:25:16 +000010586 case TBACKGND:
10587 case TSEMI:
Eric Andersencb57d552001-06-28 07:25:16 +000010588 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010589 default:
Ron Yorstonc0e00762015-10-29 11:30:55 +000010590 if ((nlflag & 1))
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010591 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010592 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010593 return n1;
10594 }
10595 }
10596}
10597
Eric Andersenc470f442003-07-28 09:56:35 +000010598static union node *
10599andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010600{
Eric Andersencb57d552001-06-28 07:25:16 +000010601 union node *n1, *n2, *n3;
10602 int t;
10603
Eric Andersencb57d552001-06-28 07:25:16 +000010604 n1 = pipeline();
10605 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010606 t = readtoken();
10607 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010608 t = NAND;
10609 } else if (t == TOR) {
10610 t = NOR;
10611 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010612 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010613 return n1;
10614 }
Eric Andersenc470f442003-07-28 09:56:35 +000010615 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010616 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010617 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010618 n3->type = t;
10619 n3->nbinary.ch1 = n1;
10620 n3->nbinary.ch2 = n2;
10621 n1 = n3;
10622 }
10623}
10624
Eric Andersenc470f442003-07-28 09:56:35 +000010625static union node *
10626pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010627{
Eric Andersencb57d552001-06-28 07:25:16 +000010628 union node *n1, *n2, *pipenode;
10629 struct nodelist *lp, *prev;
10630 int negate;
10631
10632 negate = 0;
10633 TRACE(("pipeline: entered\n"));
10634 if (readtoken() == TNOT) {
10635 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010636 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010637 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010638 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010639 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010640 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010641 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010642 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010643 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010644 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010645 pipenode->npipe.cmdlist = lp;
10646 lp->n = n1;
10647 do {
10648 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010649 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010650 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010651 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010652 prev->next = lp;
10653 } while (readtoken() == TPIPE);
10654 lp->next = NULL;
10655 n1 = pipenode;
10656 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010657 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010658 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010659 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010660 n2->type = NNOT;
10661 n2->nnot.com = n1;
10662 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010663 }
10664 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010665}
10666
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010667static union node *
10668makename(void)
10669{
10670 union node *n;
10671
Denis Vlasenko597906c2008-02-20 16:38:54 +000010672 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010673 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010674 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010675 n->narg.text = wordtext;
10676 n->narg.backquote = backquotelist;
10677 return n;
10678}
10679
10680static void
10681fixredir(union node *n, const char *text, int err)
10682{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010683 int fd;
10684
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010685 TRACE(("Fix redir %s %d\n", text, err));
10686 if (!err)
10687 n->ndup.vname = NULL;
10688
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010689 fd = bb_strtou(text, NULL, 10);
10690 if (!errno && fd >= 0)
10691 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010692 else if (LONE_DASH(text))
10693 n->ndup.dupfd = -1;
10694 else {
10695 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010696 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010697 n->ndup.vname = makename();
10698 }
10699}
10700
10701/*
10702 * Returns true if the text contains nothing to expand (no dollar signs
10703 * or backquotes).
10704 */
10705static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010706noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010707{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010708 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010709
Denys Vlasenkocd716832009-11-28 22:14:02 +010010710 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010711 if (c == CTLQUOTEMARK)
10712 continue;
10713 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010714 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010715 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010716 return 0;
10717 }
10718 return 1;
10719}
10720
10721static void
10722parsefname(void)
10723{
10724 union node *n = redirnode;
10725
10726 if (readtoken() != TWORD)
10727 raise_error_unexpected_syntax(-1);
10728 if (n->type == NHERE) {
10729 struct heredoc *here = heredoc;
10730 struct heredoc *p;
10731 int i;
10732
10733 if (quoteflag == 0)
10734 n->type = NXHERE;
10735 TRACE(("Here document %d\n", n->type));
10736 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010737 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010738 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010739 here->eofmark = wordtext;
10740 here->next = NULL;
10741 if (heredoclist == NULL)
10742 heredoclist = here;
10743 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010744 for (p = heredoclist; p->next; p = p->next)
10745 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010746 p->next = here;
10747 }
10748 } else if (n->type == NTOFD || n->type == NFROMFD) {
10749 fixredir(n, wordtext, 0);
10750 } else {
10751 n->nfile.fname = makename();
10752 }
10753}
Eric Andersencb57d552001-06-28 07:25:16 +000010754
Eric Andersenc470f442003-07-28 09:56:35 +000010755static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010756simplecmd(void)
10757{
10758 union node *args, **app;
10759 union node *n = NULL;
10760 union node *vars, **vpp;
10761 union node **rpp, *redir;
10762 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010763#if ENABLE_ASH_BASH_COMPAT
10764 smallint double_brackets_flag = 0;
10765#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010766
10767 args = NULL;
10768 app = &args;
10769 vars = NULL;
10770 vpp = &vars;
10771 redir = NULL;
10772 rpp = &redir;
10773
10774 savecheckkwd = CHKALIAS;
10775 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010776 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010777 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010778 t = readtoken();
10779 switch (t) {
10780#if ENABLE_ASH_BASH_COMPAT
10781 case TAND: /* "&&" */
10782 case TOR: /* "||" */
10783 if (!double_brackets_flag) {
10784 tokpushback = 1;
10785 goto out;
10786 }
10787 wordtext = (char *) (t == TAND ? "-a" : "-o");
10788#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010789 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010790 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010791 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010792 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010793 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010794#if ENABLE_ASH_BASH_COMPAT
10795 if (strcmp("[[", wordtext) == 0)
10796 double_brackets_flag = 1;
10797 else if (strcmp("]]", wordtext) == 0)
10798 double_brackets_flag = 0;
10799#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010800 n->narg.backquote = backquotelist;
10801 if (savecheckkwd && isassignment(wordtext)) {
10802 *vpp = n;
10803 vpp = &n->narg.next;
10804 } else {
10805 *app = n;
10806 app = &n->narg.next;
10807 savecheckkwd = 0;
10808 }
10809 break;
10810 case TREDIR:
10811 *rpp = n = redirnode;
10812 rpp = &n->nfile.next;
10813 parsefname(); /* read name of redirection file */
10814 break;
10815 case TLP:
10816 if (args && app == &args->narg.next
10817 && !vars && !redir
10818 ) {
10819 struct builtincmd *bcmd;
10820 const char *name;
10821
10822 /* We have a function */
10823 if (readtoken() != TRP)
10824 raise_error_unexpected_syntax(TRP);
10825 name = n->narg.text;
10826 if (!goodname(name)
10827 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10828 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010829 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010830 }
10831 n->type = NDEFUN;
10832 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10833 n->narg.next = parse_command();
10834 return n;
10835 }
10836 /* fall through */
10837 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010838 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010839 goto out;
10840 }
10841 }
10842 out:
10843 *app = NULL;
10844 *vpp = NULL;
10845 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010846 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010847 n->type = NCMD;
10848 n->ncmd.args = args;
10849 n->ncmd.assign = vars;
10850 n->ncmd.redirect = redir;
10851 return n;
10852}
10853
10854static union node *
10855parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010856{
Eric Andersencb57d552001-06-28 07:25:16 +000010857 union node *n1, *n2;
10858 union node *ap, **app;
10859 union node *cp, **cpp;
10860 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000010861 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000010862 int t;
10863
10864 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000010865 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000010866
Eric Andersencb57d552001-06-28 07:25:16 +000010867 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000010868 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010869 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000010870 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000010871 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010872 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010873 n1->type = NIF;
10874 n1->nif.test = list(0);
10875 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010876 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010877 n1->nif.ifpart = list(0);
10878 n2 = n1;
10879 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010880 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010881 n2 = n2->nif.elsepart;
10882 n2->type = NIF;
10883 n2->nif.test = list(0);
10884 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010885 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010886 n2->nif.ifpart = list(0);
10887 }
10888 if (lasttoken == TELSE)
10889 n2->nif.elsepart = list(0);
10890 else {
10891 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010892 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010893 }
Eric Andersenc470f442003-07-28 09:56:35 +000010894 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000010895 break;
10896 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010897 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000010898 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010899 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010900 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000010901 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010902 got = readtoken();
10903 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010904 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000010905 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010906 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010907 }
10908 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010909 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010910 break;
10911 }
10912 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010913 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000010914 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010915 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000010916 n1->type = NFOR;
10917 n1->nfor.var = wordtext;
Ron Yorstonab80e012015-08-03 13:46:00 +010010918 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010919 if (readtoken() == TIN) {
10920 app = &ap;
10921 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010922 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010923 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010924 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010925 n2->narg.text = wordtext;
10926 n2->narg.backquote = backquotelist;
10927 *app = n2;
10928 app = &n2->narg.next;
10929 }
10930 *app = NULL;
10931 n1->nfor.args = ap;
10932 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010933 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000010934 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010935 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010936 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010937 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010938 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010939 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000010940 n1->nfor.args = n2;
10941 /*
10942 * Newline or semicolon here is optional (but note
10943 * that the original Bourne shell only allowed NL).
10944 */
Ron Yorstonab80e012015-08-03 13:46:00 +010010945 if (lasttoken != TSEMI)
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 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010949 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010950 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010951 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010952 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010953 break;
10954 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010955 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000010956 n1->type = NCASE;
10957 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010958 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000010959 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010960 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010961 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010962 n2->narg.text = wordtext;
10963 n2->narg.backquote = backquotelist;
Ron Yorston383b8852015-08-03 13:46:25 +010010964 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10965 if (readtoken() != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010966 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000010967 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010968 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000010969 checkkwd = CHKNL | CHKKWD;
10970 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010971 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000010972 if (lasttoken == TLP)
10973 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010974 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000010975 cp->type = NCLIST;
10976 app = &cp->nclist.pattern;
10977 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010978 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010979 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010980 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010981 ap->narg.text = wordtext;
10982 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000010983 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000010984 break;
10985 app = &ap->narg.next;
10986 readtoken();
10987 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000010988 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000010989 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010990 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000010991 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000010992
Eric Andersenc470f442003-07-28 09:56:35 +000010993 cpp = &cp->nclist.next;
10994
10995 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010996 t = readtoken();
10997 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000010998 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010999 raise_error_unexpected_syntax(TENDCASE);
11000 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011001 }
Eric Andersenc470f442003-07-28 09:56:35 +000011002 }
Eric Andersencb57d552001-06-28 07:25:16 +000011003 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011004 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011005 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011006 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011007 n1->type = NSUBSHELL;
11008 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011009 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011010 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011011 break;
11012 case TBEGIN:
11013 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011014 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011015 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011016 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011017 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011018 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011019 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011020 }
11021
Eric Andersenc470f442003-07-28 09:56:35 +000011022 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011023 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011024
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011025 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011026 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011027 checkkwd = CHKKWD | CHKALIAS;
11028 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011029 while (readtoken() == TREDIR) {
11030 *rpp = n2 = redirnode;
11031 rpp = &n2->nfile.next;
11032 parsefname();
11033 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011034 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011035 *rpp = NULL;
11036 if (redir) {
11037 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011038 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011039 n2->type = NREDIR;
11040 n2->nredir.n = n1;
11041 n1 = n2;
11042 }
11043 n1->nredir.redirect = redir;
11044 }
Eric Andersencb57d552001-06-28 07:25:16 +000011045 return n1;
11046}
11047
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011048#if ENABLE_ASH_BASH_COMPAT
11049static int decode_dollar_squote(void)
11050{
11051 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11052 int c, cnt;
11053 char *p;
11054 char buf[4];
11055
11056 c = pgetc();
11057 p = strchr(C_escapes, c);
11058 if (p) {
11059 buf[0] = c;
11060 p = buf;
11061 cnt = 3;
11062 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11063 do {
11064 c = pgetc();
11065 *++p = c;
11066 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11067 pungetc();
11068 } else if (c == 'x') { /* \xHH */
11069 do {
11070 c = pgetc();
11071 *++p = c;
11072 } while (isxdigit(c) && --cnt);
11073 pungetc();
11074 if (cnt == 3) { /* \x but next char is "bad" */
11075 c = 'x';
11076 goto unrecognized;
11077 }
11078 } else { /* simple seq like \\ or \t */
11079 p++;
11080 }
11081 *p = '\0';
11082 p = buf;
11083 c = bb_process_escape_sequence((void*)&p);
11084 } else { /* unrecognized "\z": print both chars unless ' or " */
11085 if (c != '\'' && c != '"') {
11086 unrecognized:
11087 c |= 0x100; /* "please encode \, then me" */
11088 }
11089 }
11090 return c;
11091}
11092#endif
11093
Eric Andersencb57d552001-06-28 07:25:16 +000011094/*
11095 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11096 * is not NULL, read a here document. In the latter case, eofmark is the
11097 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011098 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011099 * is the first character of the input token or document.
11100 *
11101 * Because C does not have internal subroutines, I have simulated them
11102 * using goto's to implement the subroutine linkage. The following macros
11103 * will run code that appears at the end of readtoken1.
11104 */
Eric Andersen2870d962001-07-02 17:27:21 +000011105#define CHECKEND() {goto checkend; checkend_return:;}
11106#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11107#define PARSESUB() {goto parsesub; parsesub_return:;}
11108#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11109#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11110#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011111static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011112readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011113{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011114 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011115 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011116 char *out;
11117 int len;
11118 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011119 struct nodelist *bqlist;
11120 smallint quotef;
11121 smallint dblquote;
11122 smallint oldstyle;
11123 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011124#if ENABLE_ASH_EXPAND_PRMT
11125 smallint pssyntax; /* we are expanding a prompt string */
11126#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011127 int varnest; /* levels of variables expansion */
11128 int arinest; /* levels of arithmetic expansion */
11129 int parenlevel; /* levels of parens in arithmetic */
11130 int dqvarnest; /* levels of variables expansion within double quotes */
11131
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011132 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011133
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011134 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011135 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011136 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011137 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011138#if ENABLE_ASH_EXPAND_PRMT
11139 pssyntax = (syntax == PSSYNTAX);
11140 if (pssyntax)
11141 syntax = DQSYNTAX;
11142#endif
11143 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011144 varnest = 0;
11145 arinest = 0;
11146 parenlevel = 0;
11147 dqvarnest = 0;
11148
11149 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011150 loop:
11151 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011152 CHECKEND(); /* set c to PEOF if at end of here document */
11153 for (;;) { /* until end of line or end of word */
11154 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11155 switch (SIT(c, syntax)) {
11156 case CNL: /* '\n' */
11157 if (syntax == BASESYNTAX)
11158 goto endword; /* exit outer loop */
11159 USTPUTC(c, out);
11160 g_parsefile->linno++;
11161 setprompt_if(doprompt, 2);
11162 c = pgetc();
11163 goto loop; /* continue outer loop */
11164 case CWORD:
11165 USTPUTC(c, out);
11166 break;
11167 case CCTL:
11168 if (eofmark == NULL || dblquote)
11169 USTPUTC(CTLESC, out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011170#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011171 if (c == '\\' && bash_dollar_squote) {
11172 c = decode_dollar_squote();
11173 if (c & 0x100) {
11174 USTPUTC('\\', out);
11175 c = (unsigned char)c;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011176 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011177 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011178#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011179 USTPUTC(c, out);
11180 break;
11181 case CBACK: /* backslash */
11182 c = pgetc_without_PEOA();
11183 if (c == PEOF) {
11184 USTPUTC(CTLESC, out);
11185 USTPUTC('\\', out);
11186 pungetc();
11187 } else if (c == '\n') {
11188 setprompt_if(doprompt, 2);
11189 } else {
11190#if ENABLE_ASH_EXPAND_PRMT
11191 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011192 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011193 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011194 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011195#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011196 /* Backslash is retained if we are in "str" and next char isn't special */
11197 if (dblquote
11198 && c != '\\'
11199 && c != '`'
11200 && c != '$'
11201 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011202 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011203 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011204 }
Ron Yorston549deab2015-05-18 09:57:51 +020011205 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011206 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011207 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011208 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011209 break;
11210 case CSQUOTE:
11211 syntax = SQSYNTAX;
11212 quotemark:
11213 if (eofmark == NULL) {
11214 USTPUTC(CTLQUOTEMARK, out);
11215 }
11216 break;
11217 case CDQUOTE:
11218 syntax = DQSYNTAX;
11219 dblquote = 1;
11220 goto quotemark;
11221 case CENDQUOTE:
11222 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
Ron Yorston7e4ed262015-05-18 09:54:43 +020011223 if (eofmark != NULL && varnest == 0) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011224 USTPUTC(c, out);
11225 } else {
11226 if (dqvarnest == 0) {
11227 syntax = BASESYNTAX;
11228 dblquote = 0;
11229 }
11230 quotef = 1;
11231 goto quotemark;
11232 }
11233 break;
11234 case CVAR: /* '$' */
11235 PARSESUB(); /* parse substitution */
11236 break;
11237 case CENDVAR: /* '}' */
11238 if (varnest > 0) {
11239 varnest--;
11240 if (dqvarnest > 0) {
11241 dqvarnest--;
11242 }
11243 c = CTLENDVAR;
11244 }
11245 USTPUTC(c, out);
11246 break;
11247#if ENABLE_SH_MATH_SUPPORT
11248 case CLP: /* '(' in arithmetic */
11249 parenlevel++;
11250 USTPUTC(c, out);
11251 break;
11252 case CRP: /* ')' in arithmetic */
11253 if (parenlevel > 0) {
11254 parenlevel--;
11255 } else {
11256 if (pgetc() == ')') {
Ron Yorstonad88bde2015-05-18 09:56:16 +020011257 c = CTLENDARI;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011258 if (--arinest == 0) {
11259 syntax = prevsyntax;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011260 }
11261 } else {
11262 /*
11263 * unbalanced parens
11264 * (don't 2nd guess - no error)
11265 */
11266 pungetc();
11267 }
11268 }
11269 USTPUTC(c, out);
11270 break;
11271#endif
11272 case CBQUOTE: /* '`' */
11273 PARSEBACKQOLD();
11274 break;
11275 case CENDFILE:
11276 goto endword; /* exit outer loop */
11277 case CIGN:
11278 break;
11279 default:
11280 if (varnest == 0) {
11281#if ENABLE_ASH_BASH_COMPAT
11282 if (c == '&') {
11283 if (pgetc() == '>')
11284 c = 0x100 + '>'; /* flag &> */
11285 pungetc();
11286 }
11287#endif
11288 goto endword; /* exit outer loop */
11289 }
11290 IF_ASH_ALIAS(if (c != PEOA))
11291 USTPUTC(c, out);
11292 }
11293 c = pgetc_fast();
11294 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011295 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011296
Mike Frysinger98c52642009-04-02 10:02:37 +000011297#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011298 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011299 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011300#endif
Ron Yorston0e056f72015-07-01 16:45:40 +010011301 if (syntax != BASESYNTAX && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011302 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011303 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011304 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011305 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011306 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011307 }
11308 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011309 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011310 out = stackblock();
11311 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011312 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011313 && quotef == 0
11314 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011315 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011316 PARSEREDIR(); /* passed as params: out, c */
11317 lasttoken = TREDIR;
11318 return lasttoken;
11319 }
11320 /* else: non-number X seen, interpret it
11321 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011322 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011323 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011324 }
11325 quoteflag = quotef;
11326 backquotelist = bqlist;
11327 grabstackblock(len);
11328 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011329 lasttoken = TWORD;
11330 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011331/* end of readtoken routine */
11332
Eric Andersencb57d552001-06-28 07:25:16 +000011333/*
11334 * Check to see whether we are at the end of the here document. When this
11335 * is called, c is set to the first character of the next input line. If
11336 * we are at the end of the here document, this routine sets the c to PEOF.
11337 */
Eric Andersenc470f442003-07-28 09:56:35 +000011338checkend: {
11339 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011340#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011341 if (c == PEOA)
11342 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011343#endif
11344 if (striptabs) {
11345 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011346 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011347 }
Eric Andersenc470f442003-07-28 09:56:35 +000011348 }
11349 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011350 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011351 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011352
Eric Andersenc470f442003-07-28 09:56:35 +000011353 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011354 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11355 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011356 if (*p == '\n' && *q == '\0') {
11357 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011358 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011359 needprompt = doprompt;
11360 } else {
11361 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011362 }
11363 }
11364 }
11365 }
Eric Andersenc470f442003-07-28 09:56:35 +000011366 goto checkend_return;
11367}
Eric Andersencb57d552001-06-28 07:25:16 +000011368
Eric Andersencb57d552001-06-28 07:25:16 +000011369/*
11370 * Parse a redirection operator. The variable "out" points to a string
11371 * specifying the fd to be redirected. The variable "c" contains the
11372 * first character of the redirection operator.
11373 */
Eric Andersenc470f442003-07-28 09:56:35 +000011374parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011375 /* out is already checked to be a valid number or "" */
11376 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011377 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011378
Denis Vlasenko597906c2008-02-20 16:38:54 +000011379 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011380 if (c == '>') {
11381 np->nfile.fd = 1;
11382 c = pgetc();
11383 if (c == '>')
11384 np->type = NAPPEND;
11385 else if (c == '|')
11386 np->type = NCLOBBER;
11387 else if (c == '&')
11388 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011389 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011390 else {
11391 np->type = NTO;
11392 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011393 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011394 }
11395#if ENABLE_ASH_BASH_COMPAT
11396 else if (c == 0x100 + '>') { /* this flags &> redirection */
11397 np->nfile.fd = 1;
11398 pgetc(); /* this is '>', no need to check */
11399 np->type = NTO2;
11400 }
11401#endif
11402 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011403 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011404 c = pgetc();
11405 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011406 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011407 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011408 np = stzalloc(sizeof(struct nhere));
11409 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011410 }
11411 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011412 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011413 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011414 c = pgetc();
11415 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011416 heredoc->striptabs = 1;
11417 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011418 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011419 pungetc();
11420 }
11421 break;
11422
11423 case '&':
11424 np->type = NFROMFD;
11425 break;
11426
11427 case '>':
11428 np->type = NFROMTO;
11429 break;
11430
11431 default:
11432 np->type = NFROM;
11433 pungetc();
11434 break;
11435 }
Eric Andersencb57d552001-06-28 07:25:16 +000011436 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011437 if (fd >= 0)
11438 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011439 redirnode = np;
11440 goto parseredir_return;
11441}
Eric Andersencb57d552001-06-28 07:25:16 +000011442
Eric Andersencb57d552001-06-28 07:25:16 +000011443/*
11444 * Parse a substitution. At this point, we have read the dollar sign
11445 * and nothing else.
11446 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011447
11448/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11449 * (assuming ascii char codes, as the original implementation did) */
11450#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011451 (((unsigned)(c) - 33 < 32) \
11452 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011453parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011454 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011455 int typeloc;
11456 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011457
Eric Andersenc470f442003-07-28 09:56:35 +000011458 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011459 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011460 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011461 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011462#if ENABLE_ASH_BASH_COMPAT
11463 if (c == '\'')
11464 bash_dollar_squote = 1;
11465 else
11466#endif
11467 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011468 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011469 } else if (c == '(') {
11470 /* $(command) or $((arith)) */
Eric Andersenc470f442003-07-28 09:56:35 +000011471 if (pgetc() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011472#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011473 PARSEARITH();
11474#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011475 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011476#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011477 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011478 pungetc();
11479 PARSEBACKQNEW();
11480 }
11481 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011482 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011483 USTPUTC(CTLVAR, out);
11484 typeloc = out - (char *)stackblock();
11485 USTPUTC(VSNORMAL, out);
11486 subtype = VSNORMAL;
11487 if (c == '{') {
11488 c = pgetc();
11489 if (c == '#') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011490 c = pgetc();
11491 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011492 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011493 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011494 subtype = VSLENGTH; /* ${#VAR} */
11495 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011496 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011497 }
Eric Andersenc470f442003-07-28 09:56:35 +000011498 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011499 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011500 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011501 do {
11502 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011503 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011504 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011505 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011506 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011507 do {
11508 STPUTC(c, out);
11509 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011510 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011511 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011512 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011513 USTPUTC(c, out);
11514 c = pgetc();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011515 } else {
11516 badsub:
11517 raise_error_syntax("bad substitution");
11518 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011519 if (c != '}' && subtype == VSLENGTH) {
11520 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011521 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011522 }
Eric Andersencb57d552001-06-28 07:25:16 +000011523
Eric Andersenc470f442003-07-28 09:56:35 +000011524 STPUTC('=', out);
11525 flags = 0;
11526 if (subtype == 0) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011527 /* ${VAR...} but not $VAR or ${#VAR} */
11528 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011529 switch (c) {
11530 case ':':
Eric Andersenc470f442003-07-28 09:56:35 +000011531 c = pgetc();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011532#if ENABLE_ASH_BASH_COMPAT
11533 if (c == ':' || c == '$' || isdigit(c)) {
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011534//TODO: support more general format ${v:EXPR:EXPR},
11535// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011536 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011537 pungetc();
11538 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011539 }
11540#endif
11541 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011542 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011543 default: {
11544 static const char types[] ALIGN1 = "}-+?=";
11545 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011546 if (p == NULL)
11547 goto badsub;
11548 subtype = p - types + VSNORMAL;
11549 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011550 }
Eric Andersenc470f442003-07-28 09:56:35 +000011551 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011552 case '#': {
11553 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011554 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011555 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011556 if (c != cc)
11557 goto do_pungetc;
11558 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011559 break;
11560 }
11561#if ENABLE_ASH_BASH_COMPAT
11562 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011563 /* ${v/[/]pattern/repl} */
11564//TODO: encode pattern and repl separately.
11565// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011566 subtype = VSREPLACE;
11567 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011568 if (c != '/')
11569 goto do_pungetc;
11570 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011571 break;
11572#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011573 }
Eric Andersenc470f442003-07-28 09:56:35 +000011574 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011575 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011576 pungetc();
11577 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011578 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011579 if (subtype != VSNORMAL) {
11580 varnest++;
Ron Yorston7e4ed262015-05-18 09:54:43 +020011581 if (dblquote) {
Eric Andersenc470f442003-07-28 09:56:35 +000011582 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011583 }
11584 }
11585 }
Eric Andersenc470f442003-07-28 09:56:35 +000011586 goto parsesub_return;
11587}
Eric Andersencb57d552001-06-28 07:25:16 +000011588
Eric Andersencb57d552001-06-28 07:25:16 +000011589/*
11590 * Called to parse command substitutions. Newstyle is set if the command
11591 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11592 * list of commands (passed by reference), and savelen is the number of
11593 * characters on the top of the stack which must be preserved.
11594 */
Eric Andersenc470f442003-07-28 09:56:35 +000011595parsebackq: {
11596 struct nodelist **nlpp;
Eric Andersenc470f442003-07-28 09:56:35 +000011597 union node *n;
Ron Yorston072fc602015-07-01 16:46:18 +010011598 char *str;
Eric Andersenc470f442003-07-28 09:56:35 +000011599 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011600 smallint saveprompt = 0;
11601
Eric Andersenc470f442003-07-28 09:56:35 +000011602 str = NULL;
11603 savelen = out - (char *)stackblock();
11604 if (savelen > 0) {
Ron Yorston072fc602015-07-01 16:46:18 +010011605 str = alloca(savelen);
Eric Andersenc470f442003-07-28 09:56:35 +000011606 memcpy(str, stackblock(), savelen);
11607 }
Eric Andersenc470f442003-07-28 09:56:35 +000011608 if (oldstyle) {
11609 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011610 * treatment to some slashes, and then push the string and
11611 * reread it as input, interpreting it normally.
11612 */
Eric Andersenc470f442003-07-28 09:56:35 +000011613 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011614 size_t psavelen;
11615 char *pstr;
11616
Eric Andersenc470f442003-07-28 09:56:35 +000011617 STARTSTACKSTR(pout);
11618 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011619 int pc;
11620
11621 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011622 pc = pgetc();
11623 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011624 case '`':
11625 goto done;
11626
11627 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011628 pc = pgetc();
11629 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011630 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011631 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011632 /*
11633 * If eating a newline, avoid putting
11634 * the newline into the new character
11635 * stream (via the STPUTC after the
11636 * switch).
11637 */
11638 continue;
11639 }
11640 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011641 && (!dblquote || pc != '"')
11642 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011643 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011644 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011645 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011646 break;
11647 }
11648 /* fall through */
11649
11650 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011651 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011652 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011653 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011654
11655 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011656 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011657 needprompt = doprompt;
11658 break;
11659
11660 default:
11661 break;
11662 }
11663 STPUTC(pc, pout);
11664 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011665 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011666 STPUTC('\0', pout);
11667 psavelen = pout - (char *)stackblock();
11668 if (psavelen > 0) {
11669 pstr = grabstackstr(pout);
11670 setinputstring(pstr);
11671 }
11672 }
11673 nlpp = &bqlist;
11674 while (*nlpp)
11675 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011676 *nlpp = stzalloc(sizeof(**nlpp));
11677 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011678
11679 if (oldstyle) {
11680 saveprompt = doprompt;
11681 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011682 }
11683
Eric Andersenc470f442003-07-28 09:56:35 +000011684 n = list(2);
11685
11686 if (oldstyle)
11687 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011688 else if (readtoken() != TRP)
11689 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011690
11691 (*nlpp)->n = n;
11692 if (oldstyle) {
11693 /*
11694 * Start reading from old file again, ignoring any pushed back
11695 * tokens left from the backquote parsing
11696 */
11697 popfile();
11698 tokpushback = 0;
11699 }
11700 while (stackblocksize() <= savelen)
11701 growstackblock();
11702 STARTSTACKSTR(out);
11703 if (str) {
11704 memcpy(out, str, savelen);
11705 STADJUST(savelen, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011706 }
Ron Yorston549deab2015-05-18 09:57:51 +020011707 USTPUTC(CTLBACKQ, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011708 if (oldstyle)
11709 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011710 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011711}
11712
Mike Frysinger98c52642009-04-02 10:02:37 +000011713#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011714/*
11715 * Parse an arithmetic expansion (indicate start of one and set state)
11716 */
Eric Andersenc470f442003-07-28 09:56:35 +000011717parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011718 if (++arinest == 1) {
11719 prevsyntax = syntax;
11720 syntax = ARISYNTAX;
Eric Andersencb57d552001-06-28 07:25:16 +000011721 }
Ron Yorstonad88bde2015-05-18 09:56:16 +020011722 USTPUTC(CTLARI, out);
Eric Andersenc470f442003-07-28 09:56:35 +000011723 goto parsearith_return;
11724}
11725#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011726} /* end of readtoken */
11727
Eric Andersencb57d552001-06-28 07:25:16 +000011728/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011729 * Read the next input token.
11730 * If the token is a word, we set backquotelist to the list of cmds in
11731 * backquotes. We set quoteflag to true if any part of the word was
11732 * quoted.
11733 * If the token is TREDIR, then we set redirnode to a structure containing
11734 * the redirection.
11735 * In all cases, the variable startlinno is set to the number of the line
11736 * on which the token starts.
11737 *
11738 * [Change comment: here documents and internal procedures]
11739 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11740 * word parsing code into a separate routine. In this case, readtoken
11741 * doesn't need to have any internal procedures, but parseword does.
11742 * We could also make parseoperator in essence the main routine, and
11743 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011744 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011745#define NEW_xxreadtoken
11746#ifdef NEW_xxreadtoken
11747/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011748static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011749 '\n', '(', ')', /* singles */
11750 '&', '|', ';', /* doubles */
11751 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011752};
Eric Andersencb57d552001-06-28 07:25:16 +000011753
Denis Vlasenko834dee72008-10-07 09:18:30 +000011754#define xxreadtoken_singles 3
11755#define xxreadtoken_doubles 3
11756
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011757static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011758 TNL, TLP, TRP, /* only single occurrence allowed */
11759 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11760 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011761 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011762};
11763
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011764static int
11765xxreadtoken(void)
11766{
11767 int c;
11768
11769 if (tokpushback) {
11770 tokpushback = 0;
11771 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011772 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011773 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011774 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011775 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011776 c = pgetc_fast();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011777 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011778 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011779
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011780 if (c == '#') {
11781 while ((c = pgetc()) != '\n' && c != PEOF)
11782 continue;
11783 pungetc();
11784 } else if (c == '\\') {
11785 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011786 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011787 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011788 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011789 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011790 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011791 } else {
11792 const char *p;
11793
11794 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11795 if (c != PEOF) {
11796 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011797 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011798 needprompt = doprompt;
11799 }
11800
11801 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011802 if (p == NULL)
11803 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011804
Denis Vlasenko834dee72008-10-07 09:18:30 +000011805 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11806 int cc = pgetc();
11807 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011808 p += xxreadtoken_doubles + 1;
11809 } else {
11810 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011811#if ENABLE_ASH_BASH_COMPAT
11812 if (c == '&' && cc == '>') /* &> */
11813 break; /* return readtoken1(...) */
11814#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011815 }
11816 }
11817 }
11818 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11819 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011820 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011821 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011822
11823 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011824}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011825#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011826#define RETURN(token) return lasttoken = token
11827static int
11828xxreadtoken(void)
11829{
11830 int c;
11831
11832 if (tokpushback) {
11833 tokpushback = 0;
11834 return lasttoken;
11835 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011836 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011837 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011838 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011839 c = pgetc_fast();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011840 switch (c) {
11841 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011842 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011843 continue;
11844 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011845 while ((c = pgetc()) != '\n' && c != PEOF)
11846 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011847 pungetc();
11848 continue;
11849 case '\\':
11850 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011851 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011852 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011853 continue;
11854 }
11855 pungetc();
11856 goto breakloop;
11857 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011858 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011859 needprompt = doprompt;
11860 RETURN(TNL);
11861 case PEOF:
11862 RETURN(TEOF);
11863 case '&':
11864 if (pgetc() == '&')
11865 RETURN(TAND);
11866 pungetc();
11867 RETURN(TBACKGND);
11868 case '|':
11869 if (pgetc() == '|')
11870 RETURN(TOR);
11871 pungetc();
11872 RETURN(TPIPE);
11873 case ';':
11874 if (pgetc() == ';')
11875 RETURN(TENDCASE);
11876 pungetc();
11877 RETURN(TSEMI);
11878 case '(':
11879 RETURN(TLP);
11880 case ')':
11881 RETURN(TRP);
11882 default:
11883 goto breakloop;
11884 }
11885 }
11886 breakloop:
11887 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11888#undef RETURN
11889}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011890#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011891
11892static int
11893readtoken(void)
11894{
11895 int t;
Ron Yorston713f07d2015-10-29 16:44:56 +000011896 int kwd = checkkwd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011897#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011898 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011899#endif
11900
11901#if ENABLE_ASH_ALIAS
11902 top:
11903#endif
11904
11905 t = xxreadtoken();
11906
11907 /*
11908 * eat newlines
11909 */
Ron Yorston713f07d2015-10-29 16:44:56 +000011910 if (kwd & CHKNL) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011911 while (t == TNL) {
11912 parseheredoc();
11913 t = xxreadtoken();
11914 }
11915 }
11916
11917 if (t != TWORD || quoteflag) {
11918 goto out;
11919 }
11920
11921 /*
11922 * check for keywords
11923 */
Ron Yorston713f07d2015-10-29 16:44:56 +000011924 if (kwd & CHKKWD) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011925 const char *const *pp;
11926
11927 pp = findkwd(wordtext);
11928 if (pp) {
11929 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011930 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011931 goto out;
11932 }
11933 }
11934
11935 if (checkkwd & CHKALIAS) {
11936#if ENABLE_ASH_ALIAS
11937 struct alias *ap;
11938 ap = lookupalias(wordtext, 1);
11939 if (ap != NULL) {
11940 if (*ap->val) {
11941 pushstring(ap->val, ap);
11942 }
11943 goto top;
11944 }
11945#endif
11946 }
11947 out:
11948 checkkwd = 0;
11949#if DEBUG
11950 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011951 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011952 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020011953 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011954#endif
11955 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000011956}
11957
Ron Yorstonc0e00762015-10-29 11:30:55 +000011958static int
Ron Yorston6bd2fab2015-10-29 11:30:22 +000011959peektoken(void)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011960{
11961 int t;
11962
11963 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011964 tokpushback = 1;
Ron Yorstonc0e00762015-10-29 11:30:55 +000011965 return t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011966}
Eric Andersencb57d552001-06-28 07:25:16 +000011967
11968/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020011969 * Read and parse a command. Returns NODE_EOF on end of file.
11970 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000011971 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011972static union node *
11973parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000011974{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011975 tokpushback = 0;
Ron Yorstonc0e00762015-10-29 11:30:55 +000011976 checkkwd = 0;
11977 heredoclist = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011978 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011979 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011980 needprompt = 0;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011981 return list(1);
11982}
11983
11984/*
11985 * Input any here documents.
11986 */
11987static void
11988parseheredoc(void)
11989{
11990 struct heredoc *here;
11991 union node *n;
11992
11993 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011994 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011995
11996 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011997 setprompt_if(needprompt, 2);
11998 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011999 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012000 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012001 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012002 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012003 n->narg.text = wordtext;
12004 n->narg.backquote = backquotelist;
12005 here->here->nhere.doc = n;
12006 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012007 }
Eric Andersencb57d552001-06-28 07:25:16 +000012008}
12009
12010
12011/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012012 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012013 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012014#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012015static const char *
12016expandstr(const char *ps)
12017{
12018 union node n;
12019
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012020 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12021 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012022 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012023 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012024 popfile();
12025
12026 n.narg.type = NARG;
12027 n.narg.next = NULL;
12028 n.narg.text = wordtext;
12029 n.narg.backquote = backquotelist;
12030
Ron Yorston549deab2015-05-18 09:57:51 +020012031 expandarg(&n, NULL, EXP_QUOTED);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012032 return stackblock();
12033}
12034#endif
12035
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012036/*
12037 * Execute a command or commands contained in a string.
12038 */
12039static int
12040evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012041{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012042 union node *n;
12043 struct stackmark smark;
12044 int skip;
12045
12046 setinputstring(s);
12047 setstackmark(&smark);
12048
12049 skip = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012050 while ((n = parsecmd(0)) != NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012051 evaltree(n, 0);
12052 popstackmark(&smark);
12053 skip = evalskip;
12054 if (skip)
12055 break;
12056 }
12057 popfile();
12058
12059 skip &= mask;
12060 evalskip = skip;
12061 return skip;
Eric Andersenc470f442003-07-28 09:56:35 +000012062}
12063
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012064/*
12065 * The eval command.
12066 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012067static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012068evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012069{
12070 char *p;
12071 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012072
Denis Vlasenko68404f12008-03-17 09:00:54 +000012073 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012074 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012075 argv += 2;
12076 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012077 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012078 for (;;) {
12079 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012080 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012081 if (p == NULL)
12082 break;
12083 STPUTC(' ', concat);
12084 }
12085 STPUTC('\0', concat);
12086 p = grabstackstr(concat);
12087 }
12088 evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012089 }
12090 return exitstatus;
12091}
12092
12093/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012094 * Read and execute commands.
12095 * "Top" is nonzero for the top level command loop;
12096 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012097 */
12098static int
12099cmdloop(int top)
12100{
12101 union node *n;
12102 struct stackmark smark;
12103 int inter;
12104 int numeof = 0;
12105
12106 TRACE(("cmdloop(%d) called\n", top));
12107 for (;;) {
12108 int skip;
12109
12110 setstackmark(&smark);
12111#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012112 if (doing_jobctl)
Denys Vlasenko9c541002015-10-07 15:44:36 +020012113 showjobs(SHOW_CHANGED|SHOW_STDERR);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012114#endif
12115 inter = 0;
12116 if (iflag && top) {
12117 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012118 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012119 }
12120 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012121#if DEBUG
12122 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012123 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012124#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012125 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012126 if (!top || numeof >= 50)
12127 break;
12128 if (!stoppedjobs()) {
12129 if (!Iflag)
12130 break;
12131 out2str("\nUse \"exit\" to leave shell.\n");
12132 }
12133 numeof++;
12134 } else if (nflag == 0) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012135 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12136 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012137 numeof = 0;
12138 evaltree(n, 0);
12139 }
12140 popstackmark(&smark);
12141 skip = evalskip;
12142
12143 if (skip) {
12144 evalskip = 0;
12145 return skip & SKIPEVAL;
12146 }
12147 }
12148 return 0;
12149}
12150
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012151/*
12152 * Take commands from a file. To be compatible we should do a path
12153 * search for the file, which is necessary to find sub-commands.
12154 */
12155static char *
12156find_dot_file(char *name)
12157{
12158 char *fullname;
12159 const char *path = pathval();
12160 struct stat statb;
12161
12162 /* don't try this for absolute or relative paths */
12163 if (strchr(name, '/'))
12164 return name;
12165
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012166 /* IIRC standards do not say whether . is to be searched.
12167 * And it is even smaller this way, making it unconditional for now:
12168 */
12169 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12170 fullname = name;
12171 goto try_cur_dir;
12172 }
12173
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012174 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012175 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012176 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12177 /*
12178 * Don't bother freeing here, since it will
12179 * be freed by the caller.
12180 */
12181 return fullname;
12182 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012183 if (fullname != name)
12184 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012185 }
12186
12187 /* not found in the PATH */
12188 ash_msg_and_raise_error("%s: not found", name);
12189 /* NOTREACHED */
12190}
12191
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012192static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012193dotcmd(int argc, char **argv)
12194{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012195 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012196 struct strlist *sp;
12197 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012198
12199 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012200 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012201
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012202 if (!argv[1]) {
12203 /* bash says: "bash: .: filename argument required" */
12204 return 2; /* bash compat */
12205 }
12206
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012207 /* "false; . empty_file; echo $?" should print 0, not 1: */
12208 exitstatus = 0;
12209
Denys Vlasenko091f8312013-03-17 14:25:22 +010012210 /* This aborts if file isn't found, which is POSIXly correct.
12211 * bash returns exitcode 1 instead.
12212 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012213 fullname = find_dot_file(argv[1]);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012214 argv += 2;
12215 argc -= 2;
12216 if (argc) { /* argc > 0, argv[0] != NULL */
12217 saveparam = shellparam;
12218 shellparam.malloced = 0;
12219 shellparam.nparam = argc;
12220 shellparam.p = argv;
12221 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012222
Denys Vlasenko091f8312013-03-17 14:25:22 +010012223 /* This aborts if file can't be opened, which is POSIXly correct.
12224 * bash returns exitcode 1 instead.
12225 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012226 setinputfile(fullname, INPUT_PUSH_FILE);
12227 commandname = fullname;
12228 cmdloop(0);
12229 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012230
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012231 if (argc) {
12232 freeparam(&shellparam);
12233 shellparam = saveparam;
12234 };
12235
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012236 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012237}
12238
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012239static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012240exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012241{
12242 if (stoppedjobs())
12243 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012244 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012245 exitstatus = number(argv[1]);
12246 raise_exception(EXEXIT);
12247 /* NOTREACHED */
12248}
12249
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012250/*
12251 * Read a file containing shell functions.
12252 */
12253static void
12254readcmdfile(char *name)
12255{
12256 setinputfile(name, INPUT_PUSH_FILE);
12257 cmdloop(0);
12258 popfile();
12259}
12260
12261
Denis Vlasenkocc571512007-02-23 21:10:35 +000012262/* ============ find_command inplementation */
12263
12264/*
12265 * Resolve a command name. If you change this routine, you may have to
12266 * change the shellexec routine as well.
12267 */
12268static void
12269find_command(char *name, struct cmdentry *entry, int act, const char *path)
12270{
12271 struct tblentry *cmdp;
12272 int idx;
12273 int prev;
12274 char *fullname;
12275 struct stat statb;
12276 int e;
12277 int updatetbl;
12278 struct builtincmd *bcmd;
12279
12280 /* If name contains a slash, don't use PATH or hash table */
12281 if (strchr(name, '/') != NULL) {
12282 entry->u.index = -1;
12283 if (act & DO_ABS) {
12284 while (stat(name, &statb) < 0) {
12285#ifdef SYSV
12286 if (errno == EINTR)
12287 continue;
12288#endif
12289 entry->cmdtype = CMDUNKNOWN;
12290 return;
12291 }
12292 }
12293 entry->cmdtype = CMDNORMAL;
12294 return;
12295 }
12296
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012297/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012298
12299 updatetbl = (path == pathval());
12300 if (!updatetbl) {
12301 act |= DO_ALTPATH;
12302 if (strstr(path, "%builtin") != NULL)
12303 act |= DO_ALTBLTIN;
12304 }
12305
12306 /* If name is in the table, check answer will be ok */
12307 cmdp = cmdlookup(name, 0);
12308 if (cmdp != NULL) {
12309 int bit;
12310
12311 switch (cmdp->cmdtype) {
12312 default:
12313#if DEBUG
12314 abort();
12315#endif
12316 case CMDNORMAL:
12317 bit = DO_ALTPATH;
12318 break;
12319 case CMDFUNCTION:
12320 bit = DO_NOFUNC;
12321 break;
12322 case CMDBUILTIN:
12323 bit = DO_ALTBLTIN;
12324 break;
12325 }
12326 if (act & bit) {
12327 updatetbl = 0;
12328 cmdp = NULL;
12329 } else if (cmdp->rehash == 0)
12330 /* if not invalidated by cd, we're done */
12331 goto success;
12332 }
12333
12334 /* If %builtin not in path, check for builtin next */
12335 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012336 if (bcmd) {
12337 if (IS_BUILTIN_REGULAR(bcmd))
12338 goto builtin_success;
12339 if (act & DO_ALTPATH) {
12340 if (!(act & DO_ALTBLTIN))
12341 goto builtin_success;
12342 } else if (builtinloc <= 0) {
12343 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012344 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012345 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012346
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012347#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012348 {
12349 int applet_no = find_applet_by_name(name);
12350 if (applet_no >= 0) {
12351 entry->cmdtype = CMDNORMAL;
12352 entry->u.index = -2 - applet_no;
12353 return;
12354 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012355 }
12356#endif
12357
Denis Vlasenkocc571512007-02-23 21:10:35 +000012358 /* We have to search path. */
12359 prev = -1; /* where to start */
12360 if (cmdp && cmdp->rehash) { /* doing a rehash */
12361 if (cmdp->cmdtype == CMDBUILTIN)
12362 prev = builtinloc;
12363 else
12364 prev = cmdp->param.index;
12365 }
12366
12367 e = ENOENT;
12368 idx = -1;
12369 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012370 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012371 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012372 /* NB: code below will still use fullname
12373 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012374 idx++;
12375 if (pathopt) {
12376 if (prefix(pathopt, "builtin")) {
12377 if (bcmd)
12378 goto builtin_success;
12379 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012380 }
12381 if ((act & DO_NOFUNC)
12382 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012383 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012384 continue;
12385 }
12386 }
12387 /* if rehash, don't redo absolute path names */
12388 if (fullname[0] == '/' && idx <= prev) {
12389 if (idx < prev)
12390 continue;
12391 TRACE(("searchexec \"%s\": no change\n", name));
12392 goto success;
12393 }
12394 while (stat(fullname, &statb) < 0) {
12395#ifdef SYSV
12396 if (errno == EINTR)
12397 continue;
12398#endif
12399 if (errno != ENOENT && errno != ENOTDIR)
12400 e = errno;
12401 goto loop;
12402 }
12403 e = EACCES; /* if we fail, this will be the error */
12404 if (!S_ISREG(statb.st_mode))
12405 continue;
12406 if (pathopt) { /* this is a %func directory */
12407 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012408 /* NB: stalloc will return space pointed by fullname
12409 * (because we don't have any intervening allocations
12410 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012411 readcmdfile(fullname);
12412 cmdp = cmdlookup(name, 0);
12413 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12414 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12415 stunalloc(fullname);
12416 goto success;
12417 }
12418 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12419 if (!updatetbl) {
12420 entry->cmdtype = CMDNORMAL;
12421 entry->u.index = idx;
12422 return;
12423 }
12424 INT_OFF;
12425 cmdp = cmdlookup(name, 1);
12426 cmdp->cmdtype = CMDNORMAL;
12427 cmdp->param.index = idx;
12428 INT_ON;
12429 goto success;
12430 }
12431
12432 /* We failed. If there was an entry for this command, delete it */
12433 if (cmdp && updatetbl)
12434 delete_cmd_entry();
12435 if (act & DO_ERR)
12436 ash_msg("%s: %s", name, errmsg(e, "not found"));
12437 entry->cmdtype = CMDUNKNOWN;
12438 return;
12439
12440 builtin_success:
12441 if (!updatetbl) {
12442 entry->cmdtype = CMDBUILTIN;
12443 entry->u.cmd = bcmd;
12444 return;
12445 }
12446 INT_OFF;
12447 cmdp = cmdlookup(name, 1);
12448 cmdp->cmdtype = CMDBUILTIN;
12449 cmdp->param.cmd = bcmd;
12450 INT_ON;
12451 success:
12452 cmdp->rehash = 0;
12453 entry->cmdtype = cmdp->cmdtype;
12454 entry->u = cmdp->param;
12455}
12456
12457
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012458/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012459
Eric Andersencb57d552001-06-28 07:25:16 +000012460/*
Eric Andersencb57d552001-06-28 07:25:16 +000012461 * The trap builtin.
12462 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012463static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012464trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012465{
12466 char *action;
12467 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012468 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012469
Eric Andersenc470f442003-07-28 09:56:35 +000012470 nextopt(nullstr);
12471 ap = argptr;
12472 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012473 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012474 char *tr = trap_ptr[signo];
12475 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012476 /* note: bash adds "SIG", but only if invoked
12477 * as "bash". If called as "sh", or if set -o posix,
12478 * then it prints short signal names.
12479 * We are printing short names: */
12480 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012481 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012482 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012483 /* trap_ptr != trap only if we are in special-cased `trap` code.
12484 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012485 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012486 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012487 }
12488 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012489 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012490 if (trap_ptr != trap) {
12491 free(trap_ptr);
12492 trap_ptr = trap;
12493 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012494 */
Eric Andersencb57d552001-06-28 07:25:16 +000012495 return 0;
12496 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012497
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012498 action = NULL;
12499 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012500 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012501 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012502 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012503 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012504 if (signo < 0) {
12505 /* Mimic bash message exactly */
12506 ash_msg("%s: invalid signal specification", *ap);
12507 exitcode = 1;
12508 goto next;
12509 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012510 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012511 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012512 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012513 action = NULL;
12514 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012515 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012516 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012517 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012518 if (action)
12519 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012520 trap[signo] = action;
12521 if (signo != 0)
12522 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012523 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012524 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012525 ap++;
12526 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012527 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012528}
12529
Eric Andersenc470f442003-07-28 09:56:35 +000012530
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012531/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012532
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012533#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012534static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012535helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012536{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012537 unsigned col;
12538 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012539
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012540 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012541 "Built-in commands:\n"
12542 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012543 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012544 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012545 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012546 if (col > 60) {
12547 out1fmt("\n");
12548 col = 0;
12549 }
12550 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012551# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012552 {
12553 const char *a = applet_names;
12554 while (*a) {
12555 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12556 if (col > 60) {
12557 out1fmt("\n");
12558 col = 0;
12559 }
12560 a += strlen(a) + 1;
Eric Andersenc470f442003-07-28 09:56:35 +000012561 }
12562 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012563# endif
Eric Andersenc470f442003-07-28 09:56:35 +000012564 out1fmt("\n\n");
12565 return EXIT_SUCCESS;
12566}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012567#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012568
Flemming Madsend96ffda2013-04-07 18:47:24 +020012569#if MAX_HISTORY
12570static int FAST_FUNC
12571historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12572{
12573 show_history(line_input_state);
12574 return EXIT_SUCCESS;
12575}
12576#endif
12577
Eric Andersencb57d552001-06-28 07:25:16 +000012578/*
Eric Andersencb57d552001-06-28 07:25:16 +000012579 * The export and readonly commands.
12580 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012581static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012582exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012583{
12584 struct var *vp;
12585 char *name;
12586 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012587 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012588 char opt;
12589 int flag;
12590 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012591
Denys Vlasenkod5275882012-10-01 13:41:17 +020012592 /* "readonly" in bash accepts, but ignores -n.
12593 * We do the same: it saves a conditional in nextopt's param.
12594 */
12595 flag_off = 0;
12596 while ((opt = nextopt("np")) != '\0') {
12597 if (opt == 'n')
12598 flag_off = VEXPORT;
12599 }
12600 flag = VEXPORT;
12601 if (argv[0][0] == 'r') {
12602 flag = VREADONLY;
12603 flag_off = 0; /* readonly ignores -n */
12604 }
12605 flag_off = ~flag_off;
12606
12607 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12608 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012609 aptr = argptr;
12610 name = *aptr;
12611 if (name) {
12612 do {
12613 p = strchr(name, '=');
12614 if (p != NULL) {
12615 p++;
12616 } else {
12617 vp = *findvar(hashvar(name), name);
12618 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012619 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012620 continue;
12621 }
Eric Andersencb57d552001-06-28 07:25:16 +000012622 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012623 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012624 } while ((name = *++aptr) != NULL);
12625 return 0;
12626 }
Eric Andersencb57d552001-06-28 07:25:16 +000012627 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012628
12629 /* No arguments. Show the list of exported or readonly vars.
12630 * -n is ignored.
12631 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012632 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012633 return 0;
12634}
12635
Eric Andersencb57d552001-06-28 07:25:16 +000012636/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012637 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012638 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012639static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012640unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012641{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012642 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012643
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012644 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012645 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012646 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012647}
12648
Eric Andersencb57d552001-06-28 07:25:16 +000012649/*
Eric Andersencb57d552001-06-28 07:25:16 +000012650 * The unset builtin command. We unset the function before we unset the
12651 * variable to allow a function to be unset when there is a readonly variable
12652 * with the same name.
12653 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012654static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012655unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012656{
12657 char **ap;
12658 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012659 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012660 int ret = 0;
12661
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012662 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012663 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012664 }
Eric Andersencb57d552001-06-28 07:25:16 +000012665
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012666 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012667 if (flag != 'f') {
12668 i = unsetvar(*ap);
12669 ret |= i;
12670 if (!(i & 2))
12671 continue;
12672 }
12673 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012674 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012675 }
Eric Andersenc470f442003-07-28 09:56:35 +000012676 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012677}
12678
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012679static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012680 ' ', offsetof(struct tms, tms_utime),
12681 '\n', offsetof(struct tms, tms_stime),
12682 ' ', offsetof(struct tms, tms_cutime),
12683 '\n', offsetof(struct tms, tms_cstime),
12684 0
12685};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012686static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012687timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012688{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012689 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012690 const unsigned char *p;
12691 struct tms buf;
12692
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012693 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012694 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012695
12696 p = timescmd_str;
12697 do {
12698 t = *(clock_t *)(((char *) &buf) + p[1]);
12699 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012700 t = t % clk_tck;
12701 out1fmt("%lum%lu.%03lus%c",
12702 s / 60, s % 60,
12703 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012704 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012705 p += 2;
12706 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012707
Eric Andersencb57d552001-06-28 07:25:16 +000012708 return 0;
12709}
12710
Mike Frysinger98c52642009-04-02 10:02:37 +000012711#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012712/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012713 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012714 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012715 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012716 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012717 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012718static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012719letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012720{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012721 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012722
Denis Vlasenko68404f12008-03-17 09:00:54 +000012723 argv++;
12724 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012725 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012726 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012727 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012728 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012729
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012730 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012731}
Eric Andersenc470f442003-07-28 09:56:35 +000012732#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012733
Eric Andersenc470f442003-07-28 09:56:35 +000012734/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012735 * The read builtin. Options:
12736 * -r Do not interpret '\' specially
12737 * -s Turn off echo (tty only)
12738 * -n NCHARS Read NCHARS max
12739 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12740 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12741 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012742 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012743 * TODO: bash also has:
12744 * -a ARRAY Read into array[0],[1],etc
12745 * -d DELIM End on DELIM char, not newline
12746 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012747 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012748static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012749readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012750{
Denys Vlasenko73067272010-01-12 22:11:24 +010012751 char *opt_n = NULL;
12752 char *opt_p = NULL;
12753 char *opt_t = NULL;
12754 char *opt_u = NULL;
12755 int read_flags = 0;
12756 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012757 int i;
12758
Denys Vlasenko73067272010-01-12 22:11:24 +010012759 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012760 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012761 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012762 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012763 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012764 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012765 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012766 break;
12767 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012768 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012769 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012770 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012771 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012772 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012773 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012774 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012775 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012776 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012777 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012778 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012779 default:
12780 break;
12781 }
Eric Andersenc470f442003-07-28 09:56:35 +000012782 }
Paul Fox02eb9342005-09-07 16:56:02 +000012783
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012784 /* "read -s" needs to save/restore termios, can't allow ^C
12785 * to jump out of it.
12786 */
12787 INT_OFF;
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012788 r = shell_builtin_read(setvar0,
Denys Vlasenko73067272010-01-12 22:11:24 +010012789 argptr,
12790 bltinlookup("IFS"), /* can be NULL */
12791 read_flags,
12792 opt_n,
12793 opt_p,
12794 opt_t,
12795 opt_u
12796 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012797 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012798
Denys Vlasenko73067272010-01-12 22:11:24 +010012799 if ((uintptr_t)r > 1)
12800 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012801
Denys Vlasenko73067272010-01-12 22:11:24 +010012802 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012803}
12804
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012805static int FAST_FUNC
Denys Vlasenko6283f982015-10-07 16:56:20 +020012806umaskcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012807{
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012808 static const char permuser[3] ALIGN1 = "ogu";
Eric Andersenc470f442003-07-28 09:56:35 +000012809
Eric Andersenc470f442003-07-28 09:56:35 +000012810 mode_t mask;
Eric Andersenc470f442003-07-28 09:56:35 +000012811 int symbolic_mode = 0;
12812
12813 while (nextopt("S") != '\0') {
12814 symbolic_mode = 1;
12815 }
12816
Denis Vlasenkob012b102007-02-19 22:43:01 +000012817 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012818 mask = umask(0);
12819 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012820 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000012821
Denys Vlasenko6283f982015-10-07 16:56:20 +020012822 if (*argptr == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012823 if (symbolic_mode) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020012824 char buf[sizeof(",u=rwx,g=rwx,o=rwx")];
Eric Andersenc470f442003-07-28 09:56:35 +000012825 char *p = buf;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012826 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012827
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012828 i = 2;
12829 for (;;) {
Denys Vlasenko005c4922015-10-10 20:17:12 +020012830 *p++ = ',';
Eric Andersenc470f442003-07-28 09:56:35 +000012831 *p++ = permuser[i];
12832 *p++ = '=';
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012833 /* mask is 0..0uuugggooo. i=2 selects uuu bits */
Denys Vlasenko005c4922015-10-10 20:17:12 +020012834 if (!(mask & 0400)) *p++ = 'r';
12835 if (!(mask & 0200)) *p++ = 'w';
12836 if (!(mask & 0100)) *p++ = 'x';
12837 mask <<= 3;
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012838 if (--i < 0)
12839 break;
Eric Andersenc470f442003-07-28 09:56:35 +000012840 }
Denys Vlasenkoc1e2e002015-10-07 17:32:56 +020012841 *p = '\0';
Denys Vlasenko005c4922015-10-10 20:17:12 +020012842 puts(buf + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012843 } else {
Denys Vlasenkoec046f72015-10-07 17:57:53 +020012844 out1fmt("%04o\n", mask);
Eric Andersenc470f442003-07-28 09:56:35 +000012845 }
12846 } else {
Denys Vlasenko6283f982015-10-07 16:56:20 +020012847 char *modestr = *argptr;
12848 /* numeric umasks are taken as-is */
12849 /* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
12850 if (!isdigit(modestr[0]))
12851 mask ^= 0777;
Denys Vlasenko5711a2a2015-10-07 17:55:33 +020012852 mask = bb_parse_mode(modestr, mask);
12853 if ((unsigned)mask > 0777) {
Denys Vlasenko6283f982015-10-07 16:56:20 +020012854 ash_msg_and_raise_error("illegal mode: %s", modestr);
Eric Andersenc470f442003-07-28 09:56:35 +000012855 }
Denys Vlasenko6283f982015-10-07 16:56:20 +020012856 if (!isdigit(modestr[0]))
12857 mask ^= 0777;
12858 umask(mask);
Eric Andersenc470f442003-07-28 09:56:35 +000012859 }
12860 return 0;
12861}
12862
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012863static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012864ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012865{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012866 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012867}
12868
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012869/* ============ main() and helpers */
12870
12871/*
12872 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012873 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012874static void
12875exitshell(void)
12876{
12877 struct jmploc loc;
12878 char *p;
12879 int status;
12880
Denys Vlasenkobede2152011-09-04 16:12:33 +020012881#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
12882 save_history(line_input_state);
12883#endif
12884
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012885 status = exitstatus;
12886 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12887 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000012888 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012889/* dash bug: it just does _exit(exitstatus) here
12890 * but we have to do setjobctl(0) first!
12891 * (bug is still not fixed in dash-0.5.3 - if you run dash
12892 * under Midnight Commander, on exit from dash MC is backgrounded) */
12893 status = exitstatus;
12894 goto out;
12895 }
12896 exception_handler = &loc;
12897 p = trap[0];
12898 if (p) {
12899 trap[0] = NULL;
12900 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020012901 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012902 }
12903 flush_stdout_stderr();
12904 out:
12905 setjobctl(0);
12906 _exit(status);
12907 /* NOTREACHED */
12908}
12909
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012910static void
12911init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012912{
12913 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020012914 /* we will never free this */
12915 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012916
12917 /* from trap.c: */
12918 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010012919 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
12920 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
12921 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020012922 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012923
12924 /* from var.c: */
12925 {
12926 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012927 const char *p;
12928 struct stat st1, st2;
12929
12930 initvar();
12931 for (envp = environ; envp && *envp; envp++) {
12932 if (strchr(*envp, '=')) {
12933 setvareq(*envp, VEXPORT|VTEXTFIXED);
12934 }
12935 }
12936
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012937 setvar0("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010012938#if ENABLE_ASH_BASH_COMPAT
12939 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010012940 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020012941 if (!lookupvar("HOSTNAME")) {
12942 struct utsname uts;
12943 uname(&uts);
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020012944 setvar0("HOSTNAME", uts.nodename);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020012945 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010012946#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012947 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012948 if (p) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012949 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012950 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
12951 ) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012952 p = '\0';
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012953 }
12954 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012955 setpwd(p, 0);
12956 }
12957}
12958
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012959
12960//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010012961//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012962//usage:#define ash_full_usage "\n\n"
12963//usage: "Unix shell interpreter"
12964
12965//usage:#if ENABLE_FEATURE_SH_IS_ASH
12966//usage:# define sh_trivial_usage ash_trivial_usage
12967//usage:# define sh_full_usage ash_full_usage
12968//usage:#endif
12969//usage:#if ENABLE_FEATURE_BASH_IS_ASH
12970//usage:# define bash_trivial_usage ash_trivial_usage
12971//usage:# define bash_full_usage ash_full_usage
12972//usage:#endif
12973
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012974/*
12975 * Process the shell command line arguments.
12976 */
12977static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000012978procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012979{
12980 int i;
12981 const char *xminusc;
12982 char **xargv;
12983
12984 xargv = argv;
12985 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012986 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012987 xargv++;
12988 for (i = 0; i < NOPTS; i++)
12989 optlist[i] = 2;
12990 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010012991 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000012992 /* it already printed err message */
12993 raise_exception(EXERROR);
12994 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012995 xargv = argptr;
12996 xminusc = minusc;
12997 if (*xargv == NULL) {
12998 if (xminusc)
12999 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13000 sflag = 1;
13001 }
13002 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13003 iflag = 1;
13004 if (mflag == 2)
13005 mflag = iflag;
13006 for (i = 0; i < NOPTS; i++)
13007 if (optlist[i] == 2)
13008 optlist[i] = 0;
13009#if DEBUG == 2
13010 debug = 1;
13011#endif
13012 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13013 if (xminusc) {
13014 minusc = *xargv++;
13015 if (*xargv)
13016 goto setarg0;
13017 } else if (!sflag) {
13018 setinputfile(*xargv, 0);
13019 setarg0:
13020 arg0 = *xargv++;
13021 commandname = arg0;
13022 }
13023
13024 shellparam.p = xargv;
13025#if ENABLE_ASH_GETOPTS
13026 shellparam.optind = 1;
13027 shellparam.optoff = -1;
13028#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013029 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013030 while (*xargv) {
13031 shellparam.nparam++;
13032 xargv++;
13033 }
13034 optschanged();
13035}
13036
13037/*
13038 * Read /etc/profile or .profile.
13039 */
13040static void
13041read_profile(const char *name)
13042{
13043 int skip;
13044
13045 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13046 return;
13047 skip = cmdloop(0);
13048 popfile();
13049 if (skip)
13050 exitshell();
13051}
13052
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013053/*
13054 * This routine is called when an error or an interrupt occurs in an
13055 * interactive shell and control is returned to the main command loop.
13056 */
13057static void
13058reset(void)
13059{
13060 /* from eval.c: */
13061 evalskip = 0;
13062 loopnest = 0;
13063 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013064 g_parsefile->left_in_buffer = 0;
13065 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013066 popallfiles();
13067 /* from parser.c: */
13068 tokpushback = 0;
13069 checkkwd = 0;
13070 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013071 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013072}
13073
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013074#if PROFILE
13075static short profile_buf[16384];
13076extern int etext();
13077#endif
13078
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013079/*
13080 * Main routine. We initialize things, parse the arguments, execute
13081 * profiles if we're a login shell, and then call cmdloop to execute
13082 * commands. The setjmp call sets up the location to jump to when an
13083 * exception occurs. When an exception occurs the variable "state"
13084 * is used to figure out how far we had gotten.
13085 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013086int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013087int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013088{
Mike Frysinger98c52642009-04-02 10:02:37 +000013089 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013090 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013091 struct jmploc jmploc;
13092 struct stackmark smark;
13093
Denis Vlasenko01631112007-12-16 17:20:38 +000013094 /* Initialize global data */
13095 INIT_G_misc();
13096 INIT_G_memstack();
13097 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013098#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013099 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013100#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013101 INIT_G_cmdtable();
13102
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013103#if PROFILE
13104 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13105#endif
13106
13107#if ENABLE_FEATURE_EDITING
13108 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13109#endif
13110 state = 0;
13111 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013112 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013113 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013114
13115 reset();
13116
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013117 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013118 if (e == EXERROR)
13119 exitstatus = 2;
13120 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013121 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013122 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013123 }
13124 if (e == EXINT) {
Denys Vlasenko9c541002015-10-07 15:44:36 +020013125 newline_and_flush(stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013126 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013127
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013128 popstackmark(&smark);
13129 FORCE_INT_ON; /* enable interrupts */
13130 if (s == 1)
13131 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013132 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013133 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013134 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013135 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013136 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013137 }
13138 exception_handler = &jmploc;
13139#if DEBUG
13140 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013141 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013142 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013143#endif
13144 rootpid = getpid();
13145
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013146 init();
13147 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013148 procargs(argv);
13149
Denys Vlasenko6088e132010-12-25 23:58:42 +010013150 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013151 isloginsh = 1;
13152 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013153 const char *hp;
13154
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013155 state = 1;
13156 read_profile("/etc/profile");
13157 state1:
13158 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013159 hp = lookupvar("HOME");
13160 if (hp) {
13161 hp = concat_path_file(hp, ".profile");
13162 read_profile(hp);
13163 free((char*)hp);
13164 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013165 }
13166 state2:
13167 state = 3;
13168 if (
13169#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013170 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013171#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013172 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013173 ) {
13174 shinit = lookupvar("ENV");
13175 if (shinit != NULL && *shinit != '\0') {
13176 read_profile(shinit);
13177 }
13178 }
13179 state3:
13180 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013181 if (minusc) {
13182 /* evalstring pushes parsefile stack.
13183 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013184 * is one of stacked source fds.
13185 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013186 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013187 // ^^ not necessary since now we special-case fd 0
13188 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013189 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013190 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013191
13192 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013193#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013194 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013195 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013196 if (!hp) {
13197 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013198 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013199 hp = concat_path_file(hp, ".ash_history");
Denys Vlasenko0a0acb52015-04-18 19:36:38 +020013200 setvar0("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013201 free((char*)hp);
13202 hp = lookupvar("HISTFILE");
13203 }
13204 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013205 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013206 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013207# if ENABLE_FEATURE_SH_HISTFILESIZE
13208 hp = lookupvar("HISTFILESIZE");
13209 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13210# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013211 }
13212#endif
13213 state4: /* XXX ??? - why isn't this before the "if" statement */
13214 cmdloop(1);
13215 }
13216#if PROFILE
13217 monitor(0);
13218#endif
13219#ifdef GPROF
13220 {
13221 extern void _mcleanup(void);
13222 _mcleanup();
13223 }
13224#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013225 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013226 exitshell();
13227 /* NOTREACHED */
13228}
13229
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013230
Eric Andersendf82f612001-06-28 07:46:40 +000013231/*-
13232 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013233 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013234 *
13235 * This code is derived from software contributed to Berkeley by
13236 * Kenneth Almquist.
13237 *
13238 * Redistribution and use in source and binary forms, with or without
13239 * modification, are permitted provided that the following conditions
13240 * are met:
13241 * 1. Redistributions of source code must retain the above copyright
13242 * notice, this list of conditions and the following disclaimer.
13243 * 2. Redistributions in binary form must reproduce the above copyright
13244 * notice, this list of conditions and the following disclaimer in the
13245 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013246 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013247 * may be used to endorse or promote products derived from this software
13248 * without specific prior written permission.
13249 *
13250 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13251 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13252 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13253 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13254 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13255 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13256 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13257 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13258 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13259 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13260 * SUCH DAMAGE.
13261 */