blob: 90fb00fbd36e68d0f3ec4009e5a79c3245a0914b [file] [log] [blame]
Eric Andersendf82f612001-06-28 07:46:40 +00001/* vi: set sw=4 ts=4: */
2/*
3 * ash shell port for busybox
4 *
Denys Vlasenko73067272010-01-12 22:11:24 +01005 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Original BSD copyright notice is retained at the end of this file.
9 *
Eric Andersendf82f612001-06-28 07:46:40 +000010 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000011 * The Regents of the University of California. All rights reserved.
Eric Andersencb57d552001-06-28 07:25:16 +000012 *
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013 * Copyright (c) 1997-2005 Herbert Xu <herbert@gondor.apana.org.au>
Eric Andersen81fe1232003-07-29 06:38:40 +000014 * was re-ported from NetBSD and debianized.
15 *
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +020016 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
Eric Andersencb57d552001-06-28 07:25:16 +000017 */
18
Eric Andersenc470f442003-07-28 09:56:35 +000019/*
Denis Vlasenko653d8e72009-03-19 21:59:35 +000020 * The following should be set to reflect the type of system you have:
Eric Andersenc470f442003-07-28 09:56:35 +000021 * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
22 * define SYSV if you are running under System V.
23 * define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
24 * define DEBUG=2 to compile in and turn on debugging.
25 *
Denys Vlasenkof451b2c2012-06-09 02:06:57 +020026 * When debugging is on (DEBUG is 1 and "set -o debug" was executed),
27 * debugging info will be written to ./trace and a quit signal
28 * will generate a core dump.
Eric Andersenc470f442003-07-28 09:56:35 +000029 */
Denis Vlasenkof1733952009-03-19 23:21:55 +000030#define DEBUG 0
Denis Vlasenko653d8e72009-03-19 21:59:35 +000031/* Tweak debug output verbosity here */
32#define DEBUG_TIME 0
33#define DEBUG_PID 1
34#define DEBUG_SIG 1
35
Eric Andersenc470f442003-07-28 09:56:35 +000036#define PROFILE 0
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000037
Denis Vlasenko0e6f6612008-02-15 15:02:15 +000038#define JOBS ENABLE_ASH_JOB_CONTROL
Eric Andersenc470f442003-07-28 09:56:35 +000039
Denis Vlasenkob012b102007-02-19 22:43:01 +000040#include <paths.h>
41#include <setjmp.h>
42#include <fnmatch.h>
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020043#include <sys/times.h>
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020044#include <sys/utsname.h> /* for setting $HOSTNAME */
Denys Vlasenko73067272010-01-12 22:11:24 +010045
Denys Vlasenko20704f02011-03-23 17:59:27 +010046#include "busybox.h" /* for applet_names */
47#include "unicode.h"
48
Denys Vlasenko73067272010-01-12 22:11:24 +010049#include "shell_common.h"
Denys Vlasenko26777aa2010-11-22 23:49:10 +010050#if ENABLE_SH_MATH_SUPPORT
51# include "math.h"
52#endif
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020053#if ENABLE_ASH_RANDOM_SUPPORT
54# include "random.h"
Denys Vlasenko36df0482009-10-19 16:07:28 +020055#else
56# define CLEAR_RANDOM_T(rnd) ((void)0)
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020057#endif
Denis Vlasenko61befda2008-11-25 01:36:03 +000058
Denys Vlasenko1fcbff22010-06-26 02:40:08 +020059#include "NUM_APPLETS.h"
Denys Vlasenko14974842010-03-23 01:08:26 +010060#if NUM_APPLETS == 1
Denis Vlasenko61befda2008-11-25 01:36:03 +000061/* STANDALONE does not make sense, and won't compile */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020062# undef CONFIG_FEATURE_SH_STANDALONE
63# undef ENABLE_FEATURE_SH_STANDALONE
64# undef IF_FEATURE_SH_STANDALONE
Denys Vlasenko14974842010-03-23 01:08:26 +010065# undef IF_NOT_FEATURE_SH_STANDALONE
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020066# define ENABLE_FEATURE_SH_STANDALONE 0
67# define IF_FEATURE_SH_STANDALONE(...)
68# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
Eric Andersencb57d552001-06-28 07:25:16 +000069#endif
70
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000071#ifndef PIPE_BUF
Denis Vlasenko653d8e72009-03-19 21:59:35 +000072# define PIPE_BUF 4096 /* amount of buffering in a pipe */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000073#endif
74
Denys Vlasenko153fcaa2010-02-21 05:17:41 +010075#if !BB_MMU
Denis Vlasenko653d8e72009-03-19 21:59:35 +000076# error "Do not even bother, ash will not run on NOMMU machine"
Denis Vlasenkob012b102007-02-19 22:43:01 +000077#endif
78
Denys Vlasenko771f1992010-07-16 14:31:34 +020079//config:config ASH
80//config: bool "ash"
81//config: default y
82//config: depends on !NOMMU
83//config: help
84//config: Tha 'ash' shell adds about 60k in the default configuration and is
85//config: the most complete and most pedantically correct shell included with
86//config: busybox. This shell is actually a derivative of the Debian 'dash'
87//config: shell (by Herbert Xu), which was created by porting the 'ash' shell
88//config: (written by Kenneth Almquist) from NetBSD.
89//config:
90//config:config ASH_BASH_COMPAT
91//config: bool "bash-compatible extensions"
92//config: default y
93//config: depends on ASH
94//config: help
95//config: Enable bash-compatible extensions.
96//config:
Denys Vlasenko046341e2011-02-04 17:53:59 +010097//config:config ASH_IDLE_TIMEOUT
98//config: bool "Idle timeout variable"
99//config: default n
100//config: depends on ASH
101//config: help
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100102//config: Enables bash-like auto-logout after $TMOUT seconds of idle time.
Denys Vlasenko046341e2011-02-04 17:53:59 +0100103//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200104//config:config ASH_JOB_CONTROL
105//config: bool "Job control"
106//config: default y
107//config: depends on ASH
108//config: help
109//config: Enable job control in the ash shell.
110//config:
111//config:config ASH_ALIAS
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100112//config: bool "Alias support"
Denys Vlasenko771f1992010-07-16 14:31:34 +0200113//config: default y
114//config: depends on ASH
115//config: help
116//config: Enable alias support in the ash shell.
117//config:
118//config:config ASH_GETOPTS
119//config: bool "Builtin getopt to parse positional parameters"
120//config: default y
121//config: depends on ASH
122//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100123//config: Enable support for getopts builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200124//config:
125//config:config ASH_BUILTIN_ECHO
126//config: bool "Builtin version of 'echo'"
127//config: default y
128//config: depends on ASH
129//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100130//config: Enable support for echo builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200131//config:
132//config:config ASH_BUILTIN_PRINTF
133//config: bool "Builtin version of 'printf'"
134//config: default y
135//config: depends on ASH
136//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100137//config: Enable support for printf builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200138//config:
139//config:config ASH_BUILTIN_TEST
140//config: bool "Builtin version of 'test'"
141//config: default y
142//config: depends on ASH
143//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100144//config: Enable support for test builtin in ash.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200145//config:
Denys Vlasenko2ec34962014-09-08 16:52:39 +0200146//config:config ASH_HELP
147//config: bool "help builtin"
148//config: default y
149//config: depends on ASH
150//config: help
151//config: Enable help builtin in ash.
152//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200153//config:config ASH_CMDCMD
154//config: bool "'command' command to override shell builtins"
155//config: default y
156//config: depends on ASH
157//config: help
158//config: Enable support for the ash 'command' builtin, which allows
159//config: you to run the specified command with the specified arguments,
160//config: even when there is an ash builtin command with the same name.
161//config:
162//config:config ASH_MAIL
163//config: bool "Check for new mail on interactive shells"
164//config: default n
165//config: depends on ASH
166//config: help
Denys Vlasenko8c52f802011-02-04 17:36:21 +0100167//config: Enable "check for new mail" function in the ash shell.
Denys Vlasenko771f1992010-07-16 14:31:34 +0200168//config:
169//config:config ASH_OPTIMIZE_FOR_SIZE
170//config: bool "Optimize for size instead of speed"
171//config: default y
172//config: depends on ASH
173//config: help
174//config: Compile ash for reduced size at the price of speed.
175//config:
176//config:config ASH_RANDOM_SUPPORT
177//config: bool "Pseudorandom generator and $RANDOM variable"
178//config: default y
179//config: depends on ASH
180//config: help
181//config: Enable pseudorandom generator and dynamic variable "$RANDOM".
182//config: Each read of "$RANDOM" will generate a new pseudorandom value.
183//config: You can reset the generator by using a specified start value.
184//config: After "unset RANDOM" the generator will switch off and this
185//config: variable will no longer have special treatment.
186//config:
187//config:config ASH_EXPAND_PRMT
188//config: bool "Expand prompt string"
189//config: default y
190//config: depends on ASH
191//config: help
192//config: "PS#" may contain volatile content, such as backquote commands.
193//config: This option recreates the prompt string from the environment
194//config: variable each time it is displayed.
Denys Vlasenko51ca7762010-07-16 17:16:40 +0200195//config:
Denys Vlasenko771f1992010-07-16 14:31:34 +0200196
Denys Vlasenko20704f02011-03-23 17:59:27 +0100197//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP))
198//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh))
199//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash))
200
201//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o
202//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o
203
Denis Vlasenkob012b102007-02-19 22:43:01 +0000204
Denis Vlasenko01631112007-12-16 17:20:38 +0000205/* ============ Hash table sizes. Configurable. */
206
207#define VTABSIZE 39
208#define ATABSIZE 39
209#define CMDTABLESIZE 31 /* should be prime */
210
211
Denis Vlasenkob012b102007-02-19 22:43:01 +0000212/* ============ Shell options */
213
214static const char *const optletters_optnames[] = {
215 "e" "errexit",
216 "f" "noglob",
217 "I" "ignoreeof",
218 "i" "interactive",
219 "m" "monitor",
220 "n" "noexec",
221 "s" "stdin",
222 "x" "xtrace",
223 "v" "verbose",
224 "C" "noclobber",
225 "a" "allexport",
226 "b" "notify",
227 "u" "nounset",
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100228 "\0" "vi"
Michael Abbott359da5e2009-12-04 23:03:29 +0100229#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenkoe9ac32a2009-12-05 02:01:25 +0100230 ,"\0" "pipefail"
Michael Abbott359da5e2009-12-04 23:03:29 +0100231#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000232#if DEBUG
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000233 ,"\0" "nolog"
234 ,"\0" "debug"
Denis Vlasenkob012b102007-02-19 22:43:01 +0000235#endif
236};
237
Denys Vlasenko285ad152009-12-04 23:02:27 +0100238#define optletters(n) optletters_optnames[n][0]
239#define optnames(n) (optletters_optnames[n] + 1)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000240
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000241enum { NOPTS = ARRAY_SIZE(optletters_optnames) };
Denis Vlasenkob012b102007-02-19 22:43:01 +0000242
Eric Andersenc470f442003-07-28 09:56:35 +0000243
Denis Vlasenkob012b102007-02-19 22:43:01 +0000244/* ============ Misc data */
Eric Andersenc470f442003-07-28 09:56:35 +0000245
Denys Vlasenkoea8b2522010-06-02 12:57:26 +0200246#define msg_illnum "Illegal number: %s"
Denis Vlasenkoaa744452007-02-23 01:04:22 +0000247
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +0000248/*
Eric Andersenc470f442003-07-28 09:56:35 +0000249 * We enclose jmp_buf in a structure so that we can declare pointers to
250 * jump locations. The global variable handler contains the location to
Denis Vlasenkof1733952009-03-19 23:21:55 +0000251 * jump to when an exception occurs, and the global variable exception_type
Eric Andersenaff114c2004-04-14 17:51:38 +0000252 * contains a code identifying the exception. To implement nested
Eric Andersenc470f442003-07-28 09:56:35 +0000253 * exception handlers, the user should save the value of handler on entry
254 * to an inner scope, set handler to point to a jmploc structure for the
255 * inner scope, and restore handler on exit from the scope.
256 */
Eric Andersenc470f442003-07-28 09:56:35 +0000257struct jmploc {
258 jmp_buf loc;
259};
Denis Vlasenko01631112007-12-16 17:20:38 +0000260
261struct globals_misc {
262 /* pid of main shell */
263 int rootpid;
264 /* shell level: 0 for the main shell, 1 for its children, and so on */
265 int shlvl;
266#define rootshell (!shlvl)
267 char *minusc; /* argument to -c option */
268
269 char *curdir; // = nullstr; /* current working directory */
270 char *physdir; // = nullstr; /* physical working directory */
271
272 char *arg0; /* value of $0 */
273
274 struct jmploc *exception_handler;
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000275
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200276 volatile int suppress_int; /* counter */
277 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000278 /* last pending signal */
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200279 volatile /*sig_atomic_t*/ smallint pending_sig;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000280 smallint exception_type; /* kind of exception (0..5) */
Denis Vlasenko01631112007-12-16 17:20:38 +0000281 /* exceptions */
Eric Andersenc470f442003-07-28 09:56:35 +0000282#define EXINT 0 /* SIGINT received */
283#define EXERROR 1 /* a generic error */
284#define EXSHELLPROC 2 /* execute a shell procedure */
285#define EXEXEC 3 /* command execution failed */
286#define EXEXIT 4 /* exit the shell */
287#define EXSIG 5 /* trapped signal in wait(1) */
Eric Andersen2870d962001-07-02 17:27:21 +0000288
Denis Vlasenko01631112007-12-16 17:20:38 +0000289 smallint isloginsh;
Denis Vlasenkob07a4962008-06-22 13:16:23 +0000290 char nullstr[1]; /* zero length string */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000291
292 char optlist[NOPTS];
293#define eflag optlist[0]
294#define fflag optlist[1]
295#define Iflag optlist[2]
296#define iflag optlist[3]
297#define mflag optlist[4]
298#define nflag optlist[5]
299#define sflag optlist[6]
300#define xflag optlist[7]
301#define vflag optlist[8]
302#define Cflag optlist[9]
303#define aflag optlist[10]
304#define bflag optlist[11]
305#define uflag optlist[12]
306#define viflag optlist[13]
Michael Abbott359da5e2009-12-04 23:03:29 +0100307#if ENABLE_ASH_BASH_COMPAT
308# define pipefail optlist[14]
309#else
310# define pipefail 0
311#endif
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000312#if DEBUG
Michael Abbott359da5e2009-12-04 23:03:29 +0100313# define nolog optlist[14 + ENABLE_ASH_BASH_COMPAT]
314# define debug optlist[15 + ENABLE_ASH_BASH_COMPAT]
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000315#endif
316
317 /* trap handler commands */
Denis Vlasenko01631112007-12-16 17:20:38 +0000318 /*
319 * Sigmode records the current value of the signal handlers for the various
320 * modes. A value of zero means that the current handler is not known.
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000321 * S_HARD_IGN indicates that the signal was ignored on entry to the shell.
Denis Vlasenko01631112007-12-16 17:20:38 +0000322 */
323 char sigmode[NSIG - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +0000324#define S_DFL 1 /* default signal handling (SIG_DFL) */
325#define S_CATCH 2 /* signal is caught */
326#define S_IGN 3 /* signal is ignored (SIG_IGN) */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000327#define S_HARD_IGN 4 /* signal is ignored permenantly */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000328
Denis Vlasenko01631112007-12-16 17:20:38 +0000329 /* indicates specified signal received */
Denis Vlasenko4b875702009-03-19 13:30:04 +0000330 uint8_t gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
Denys Vlasenko238bf182010-05-18 15:49:07 +0200331 uint8_t may_have_traps; /* 0: definitely no traps are set, 1: some traps may be set */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000332 char *trap[NSIG];
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200333 char **trap_ptr; /* used only by "trap hack" */
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000334
335 /* Rarely referenced stuff */
336#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200337 random_t random_gen;
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000338#endif
339 pid_t backgndpid; /* pid of last background process */
340 smallint job_warning; /* user was warned about stopped jobs (can be 2, 1 or 0). */
Denis Vlasenko01631112007-12-16 17:20:38 +0000341};
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000342extern struct globals_misc *const ash_ptr_to_globals_misc;
343#define G_misc (*ash_ptr_to_globals_misc)
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000344#define rootpid (G_misc.rootpid )
345#define shlvl (G_misc.shlvl )
346#define minusc (G_misc.minusc )
347#define curdir (G_misc.curdir )
348#define physdir (G_misc.physdir )
349#define arg0 (G_misc.arg0 )
Denis Vlasenko01631112007-12-16 17:20:38 +0000350#define exception_handler (G_misc.exception_handler)
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000351#define exception_type (G_misc.exception_type )
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200352#define suppress_int (G_misc.suppress_int )
353#define pending_int (G_misc.pending_int )
354#define pending_sig (G_misc.pending_sig )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000355#define isloginsh (G_misc.isloginsh )
356#define nullstr (G_misc.nullstr )
357#define optlist (G_misc.optlist )
358#define sigmode (G_misc.sigmode )
359#define gotsig (G_misc.gotsig )
Denys Vlasenko238bf182010-05-18 15:49:07 +0200360#define may_have_traps (G_misc.may_have_traps )
Denis Vlasenko26bc57d2008-06-27 00:29:34 +0000361#define trap (G_misc.trap )
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200362#define trap_ptr (G_misc.trap_ptr )
Denys Vlasenko3ea2e822009-10-09 20:59:04 +0200363#define random_gen (G_misc.random_gen )
Denis Vlasenko448d30e2008-06-27 00:24:11 +0000364#define backgndpid (G_misc.backgndpid )
365#define job_warning (G_misc.job_warning)
Denis Vlasenko01631112007-12-16 17:20:38 +0000366#define INIT_G_misc() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +0000367 (*(struct globals_misc**)&ash_ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \
368 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +0000369 curdir = nullstr; \
370 physdir = nullstr; \
Denys Vlasenko21d87d42009-09-25 00:06:51 +0200371 trap_ptr = trap; \
Denis Vlasenko01631112007-12-16 17:20:38 +0000372} while (0)
373
374
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000375/* ============ DEBUG */
376#if DEBUG
377static void trace_printf(const char *fmt, ...);
378static void trace_vprintf(const char *fmt, va_list va);
379# define TRACE(param) trace_printf param
380# define TRACEV(param) trace_vprintf param
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000381# define close(fd) do { \
382 int dfd = (fd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000383 if (close(dfd) < 0) \
Denys Vlasenko883cea42009-07-11 15:31:59 +0200384 bb_error_msg("bug on %d: closing %d(0x%x)", \
Denis Vlasenko1bb3d7e2009-03-20 07:45:36 +0000385 __LINE__, dfd, dfd); \
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +0000386} while (0)
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000387#else
388# define TRACE(param)
389# define TRACEV(param)
390#endif
391
392
Denis Vlasenko559691a2008-10-05 18:39:31 +0000393/* ============ Utility functions */
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000394#define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0)
395
Denys Vlasenko1961aea2013-02-26 00:36:53 +0100396#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c)))
397#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c)))
398
Denis Vlasenko559691a2008-10-05 18:39:31 +0000399static int isdigit_str9(const char *str)
400{
401 int maxlen = 9 + 1; /* max 9 digits: 999999999 */
402 while (--maxlen && isdigit(*str))
403 str++;
404 return (*str == '\0');
405}
Denis Vlasenko01631112007-12-16 17:20:38 +0000406
Denys Vlasenko8837c5d2010-06-02 12:56:18 +0200407static const char *var_end(const char *var)
408{
409 while (*var)
410 if (*var++ == '=')
411 break;
412 return var;
413}
414
Denis Vlasenko559691a2008-10-05 18:39:31 +0000415
416/* ============ Interrupts / exceptions */
Denys Vlasenko66c5b122011-02-08 05:07:02 +0100417
418static void exitshell(void) NORETURN;
419
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +0000420/*
Eric Andersen2870d962001-07-02 17:27:21 +0000421 * These macros allow the user to suspend the handling of interrupt signals
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000422 * over a period of time. This is similar to SIGHOLD or to sigblock, but
Eric Andersen2870d962001-07-02 17:27:21 +0000423 * much more efficient and portable. (But hacking the kernel is so much
424 * more fun than worrying about efficiency and portability. :-))
425 */
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000426#define INT_OFF do { \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200427 suppress_int++; \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000428 xbarrier(); \
429} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000430
431/*
432 * Called to raise an exception. Since C doesn't include exceptions, we
433 * just do a longjmp to the exception handler. The type of exception is
Denis Vlasenko4b875702009-03-19 13:30:04 +0000434 * stored in the global variable "exception_type".
Denis Vlasenkob012b102007-02-19 22:43:01 +0000435 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000436static void raise_exception(int) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000437static void
438raise_exception(int e)
439{
440#if DEBUG
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000441 if (exception_handler == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000442 abort();
443#endif
444 INT_OFF;
Denis Vlasenko7f88e342009-03-19 03:36:18 +0000445 exception_type = e;
Denis Vlasenko2da584f2007-02-19 22:44:05 +0000446 longjmp(exception_handler->loc, 1);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000447}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000448#if DEBUG
449#define raise_exception(e) do { \
450 TRACE(("raising exception %d on line %d\n", (e), __LINE__)); \
451 raise_exception(e); \
452} while (0)
453#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000454
455/*
456 * Called from trap.c when a SIGINT is received. (If the user specifies
457 * that SIGINT is to be trapped or ignored using the trap builtin, then
458 * this routine is not called.) Suppressint is nonzero when interrupts
459 * are held using the INT_OFF macro. (The test for iflag is just
460 * defensive programming.)
461 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000462static void raise_interrupt(void) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000463static void
464raise_interrupt(void)
465{
Denis Vlasenko4b875702009-03-19 13:30:04 +0000466 int ex_type;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000467
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200468 pending_int = 0;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +0000469 /* Signal is not automatically unmasked after it is raised,
470 * do it ourself - unmask all signals */
Denis Vlasenko3f165fa2008-03-17 08:29:08 +0000471 sigprocmask_allsigs(SIG_UNBLOCK);
Denys Vlasenko238bf182010-05-18 15:49:07 +0200472 /* pending_sig = 0; - now done in signal_handler() */
Denis Vlasenko7c139b42007-03-21 20:17:27 +0000473
Denis Vlasenko4b875702009-03-19 13:30:04 +0000474 ex_type = EXSIG;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000475 if (gotsig[SIGINT - 1] && !trap[SIGINT]) {
476 if (!(rootshell && iflag)) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +0000477 /* Kill ourself with SIGINT */
Denis Vlasenkob012b102007-02-19 22:43:01 +0000478 signal(SIGINT, SIG_DFL);
479 raise(SIGINT);
480 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000481 ex_type = EXINT;
Denis Vlasenkob012b102007-02-19 22:43:01 +0000482 }
Denis Vlasenko4b875702009-03-19 13:30:04 +0000483 raise_exception(ex_type);
Denis Vlasenkob012b102007-02-19 22:43:01 +0000484 /* NOTREACHED */
485}
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000486#if DEBUG
487#define raise_interrupt() do { \
488 TRACE(("raising interrupt on line %d\n", __LINE__)); \
489 raise_interrupt(); \
490} while (0)
491#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +0000492
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000493static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000494int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000495{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000496 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200497 if (--suppress_int == 0 && pending_int) {
Denis Vlasenkob012b102007-02-19 22:43:01 +0000498 raise_interrupt();
499 }
500}
501#define INT_ON int_on()
Denis Vlasenko5e34ff22009-04-21 11:09:40 +0000502static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000503force_int_on(void)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000504{
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +0000505 xbarrier();
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200506 suppress_int = 0;
507 if (pending_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000508 raise_interrupt();
509}
510#define FORCE_INT_ON force_int_on()
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000511
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200512#define SAVE_INT(v) ((v) = suppress_int)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000513
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000514#define RESTORE_INT(v) do { \
515 xbarrier(); \
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200516 suppress_int = (v); \
517 if (suppress_int == 0 && pending_int) \
Denis Vlasenko843cbd52008-06-27 00:23:18 +0000518 raise_interrupt(); \
519} while (0)
Denis Vlasenkob012b102007-02-19 22:43:01 +0000520
Glenn L McGrath9fef17d2002-08-22 18:41:20 +0000521
Denis Vlasenkobc54cff2007-02-23 01:05:52 +0000522/* ============ Stdout/stderr output */
Eric Andersenc470f442003-07-28 09:56:35 +0000523
Eric Andersenc470f442003-07-28 09:56:35 +0000524static void
Denis Vlasenkob012b102007-02-19 22:43:01 +0000525outstr(const char *p, FILE *file)
Denis Vlasenkoe5570da2007-02-19 22:41:55 +0000526{
Denis Vlasenkob012b102007-02-19 22:43:01 +0000527 INT_OFF;
528 fputs(p, file);
529 INT_ON;
530}
531
532static void
533flush_stdout_stderr(void)
534{
535 INT_OFF;
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100536 fflush_all();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000537 INT_ON;
538}
539
540static void
541outcslow(int c, FILE *dest)
542{
543 INT_OFF;
544 putc(c, dest);
545 fflush(dest);
546 INT_ON;
547}
548
549static int out1fmt(const char *, ...) __attribute__((__format__(__printf__,1,2)));
550static int
551out1fmt(const char *fmt, ...)
552{
553 va_list ap;
554 int r;
555
556 INT_OFF;
557 va_start(ap, fmt);
558 r = vprintf(fmt, ap);
559 va_end(ap);
560 INT_ON;
561 return r;
562}
563
564static int fmtstr(char *, size_t, const char *, ...) __attribute__((__format__(__printf__,3,4)));
565static int
566fmtstr(char *outbuf, size_t length, const char *fmt, ...)
567{
568 va_list ap;
569 int ret;
570
571 va_start(ap, fmt);
572 INT_OFF;
573 ret = vsnprintf(outbuf, length, fmt, ap);
574 va_end(ap);
575 INT_ON;
576 return ret;
577}
578
579static void
580out1str(const char *p)
581{
582 outstr(p, stdout);
583}
584
585static void
586out2str(const char *p)
587{
588 outstr(p, stderr);
Denys Vlasenko8131eea2009-11-02 14:19:51 +0100589 flush_stdout_stderr();
Denis Vlasenkob012b102007-02-19 22:43:01 +0000590}
591
592
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000593/* ============ Parser structures */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +0000594
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000595/* control characters in argument strings */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100596#define CTL_FIRST CTLESC
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200597#define CTLESC ((unsigned char)'\201') /* escape next character */
598#define CTLVAR ((unsigned char)'\202') /* variable defn */
599#define CTLENDVAR ((unsigned char)'\203')
600#define CTLBACKQ ((unsigned char)'\204')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000601#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
602/* CTLBACKQ | CTLQUOTE == '\205' */
Denys Vlasenkob6c84342009-08-29 20:23:20 +0200603#define CTLARI ((unsigned char)'\206') /* arithmetic expression */
604#define CTLENDARI ((unsigned char)'\207')
605#define CTLQUOTEMARK ((unsigned char)'\210')
Denys Vlasenko2ce42e92009-11-29 02:18:13 +0100606#define CTL_LAST CTLQUOTEMARK
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000607
608/* variable substitution byte (follows CTLVAR) */
609#define VSTYPE 0x0f /* type of variable substitution */
610#define VSNUL 0x10 /* colon--treat the empty string as unset */
611#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
612
613/* values of VSTYPE field */
Denis Vlasenko92e13c22008-03-25 01:17:40 +0000614#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
615#define VSMINUS 0x2 /* ${var-text} */
616#define VSPLUS 0x3 /* ${var+text} */
617#define VSQUESTION 0x4 /* ${var?message} */
618#define VSASSIGN 0x5 /* ${var=text} */
619#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
620#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
621#define VSTRIMLEFT 0x8 /* ${var#pattern} */
622#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
623#define VSLENGTH 0xa /* ${#var} */
624#if ENABLE_ASH_BASH_COMPAT
625#define VSSUBSTR 0xc /* ${var:position:length} */
626#define VSREPLACE 0xd /* ${var/pattern/replacement} */
627#define VSREPLACEALL 0xe /* ${var//pattern/replacement} */
628#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000629
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000630static const char dolatstr[] ALIGN1 = {
631 CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
632};
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +0000633
Denis Vlasenko559691a2008-10-05 18:39:31 +0000634#define NCMD 0
635#define NPIPE 1
636#define NREDIR 2
637#define NBACKGND 3
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000638#define NSUBSHELL 4
Denis Vlasenko559691a2008-10-05 18:39:31 +0000639#define NAND 5
640#define NOR 6
641#define NSEMI 7
642#define NIF 8
643#define NWHILE 9
644#define NUNTIL 10
645#define NFOR 11
646#define NCASE 12
647#define NCLIST 13
648#define NDEFUN 14
649#define NARG 15
650#define NTO 16
651#if ENABLE_ASH_BASH_COMPAT
652#define NTO2 17
653#endif
654#define NCLOBBER 18
655#define NFROM 19
656#define NFROMTO 20
657#define NAPPEND 21
658#define NTOFD 22
659#define NFROMFD 23
660#define NHERE 24
661#define NXHERE 25
662#define NNOT 26
Denis Vlasenko340299a2008-11-21 10:36:36 +0000663#define N_NUMBER 27
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000664
665union node;
666
667struct ncmd {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000668 smallint type; /* Nxxxx */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000669 union node *assign;
670 union node *args;
671 union node *redirect;
672};
673
674struct npipe {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000675 smallint type;
676 smallint pipe_backgnd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000677 struct nodelist *cmdlist;
678};
679
680struct nredir {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000681 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000682 union node *n;
683 union node *redirect;
684};
685
686struct nbinary {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000687 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000688 union node *ch1;
689 union node *ch2;
690};
691
692struct nif {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000693 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000694 union node *test;
695 union node *ifpart;
696 union node *elsepart;
697};
698
699struct nfor {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000700 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000701 union node *args;
702 union node *body;
703 char *var;
704};
705
706struct ncase {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000707 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000708 union node *expr;
709 union node *cases;
710};
711
712struct nclist {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000713 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000714 union node *next;
715 union node *pattern;
716 union node *body;
717};
718
719struct narg {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000720 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000721 union node *next;
722 char *text;
723 struct nodelist *backquote;
724};
725
Denis Vlasenko559691a2008-10-05 18:39:31 +0000726/* nfile and ndup layout must match!
727 * NTOFD (>&fdnum) uses ndup structure, but we may discover mid-flight
728 * that it is actually NTO2 (>&file), and change its type.
729 */
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000730struct nfile {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000731 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000732 union node *next;
733 int fd;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000734 int _unused_dupfd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000735 union node *fname;
736 char *expfname;
737};
738
739struct ndup {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000740 smallint type;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000741 union node *next;
742 int fd;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000743 int dupfd;
744 union node *vname;
Denis Vlasenko559691a2008-10-05 18:39:31 +0000745 char *_unused_expfname;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000746};
747
748struct nhere {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000749 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000750 union node *next;
751 int fd;
752 union node *doc;
753};
754
755struct nnot {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000756 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000757 union node *com;
758};
759
760union node {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +0000761 smallint type;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000762 struct ncmd ncmd;
763 struct npipe npipe;
764 struct nredir nredir;
765 struct nbinary nbinary;
766 struct nif nif;
767 struct nfor nfor;
768 struct ncase ncase;
769 struct nclist nclist;
770 struct narg narg;
771 struct nfile nfile;
772 struct ndup ndup;
773 struct nhere nhere;
774 struct nnot nnot;
775};
776
Denys Vlasenko86e83ec2009-07-23 22:07:07 +0200777/*
778 * NODE_EOF is returned by parsecmd when it encounters an end of file.
779 * It must be distinct from NULL.
780 */
781#define NODE_EOF ((union node *) -1L)
782
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000783struct nodelist {
784 struct nodelist *next;
785 union node *n;
786};
787
788struct funcnode {
789 int count;
790 union node n;
791};
792
Denis Vlasenko5651bfc2007-02-23 21:08:58 +0000793/*
794 * Free a parse tree.
795 */
796static void
797freefunc(struct funcnode *f)
798{
799 if (f && --f->count < 0)
800 free(f);
801}
802
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000803
804/* ============ Debugging output */
805
806#if DEBUG
807
808static FILE *tracefile;
809
810static void
811trace_printf(const char *fmt, ...)
812{
813 va_list va;
814
815 if (debug != 1)
816 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000817 if (DEBUG_TIME)
818 fprintf(tracefile, "%u ", (int) time(NULL));
819 if (DEBUG_PID)
820 fprintf(tracefile, "[%u] ", (int) getpid());
821 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200822 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000823 va_start(va, fmt);
824 vfprintf(tracefile, fmt, va);
825 va_end(va);
826}
827
828static void
829trace_vprintf(const char *fmt, va_list va)
830{
831 if (debug != 1)
832 return;
Denis Vlasenko653d8e72009-03-19 21:59:35 +0000833 if (DEBUG_TIME)
834 fprintf(tracefile, "%u ", (int) time(NULL));
835 if (DEBUG_PID)
836 fprintf(tracefile, "[%u] ", (int) getpid());
837 if (DEBUG_SIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +0200838 fprintf(tracefile, "pending s:%d i:%d(supp:%d) ", pending_sig, pending_int, suppress_int);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000839 vfprintf(tracefile, fmt, va);
840}
841
842static void
843trace_puts(const char *s)
844{
845 if (debug != 1)
846 return;
847 fputs(s, tracefile);
848}
849
850static void
851trace_puts_quoted(char *s)
852{
853 char *p;
854 char c;
855
856 if (debug != 1)
857 return;
858 putc('"', tracefile);
859 for (p = s; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100860 switch ((unsigned char)*p) {
861 case '\n': c = 'n'; goto backslash;
862 case '\t': c = 't'; goto backslash;
863 case '\r': c = 'r'; goto backslash;
864 case '\"': c = '\"'; goto backslash;
865 case '\\': c = '\\'; goto backslash;
866 case CTLESC: c = 'e'; goto backslash;
867 case CTLVAR: c = 'v'; goto backslash;
868 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
869 case CTLBACKQ: c = 'q'; goto backslash;
870 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000871 backslash:
872 putc('\\', tracefile);
873 putc(c, tracefile);
874 break;
875 default:
876 if (*p >= ' ' && *p <= '~')
877 putc(*p, tracefile);
878 else {
879 putc('\\', tracefile);
Denys Vlasenkocd716832009-11-28 22:14:02 +0100880 putc((*p >> 6) & 03, tracefile);
881 putc((*p >> 3) & 07, tracefile);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000882 putc(*p & 07, tracefile);
883 }
884 break;
885 }
886 }
887 putc('"', tracefile);
888}
889
890static void
891trace_puts_args(char **ap)
892{
893 if (debug != 1)
894 return;
895 if (!*ap)
896 return;
897 while (1) {
898 trace_puts_quoted(*ap);
899 if (!*++ap) {
900 putc('\n', tracefile);
901 break;
902 }
903 putc(' ', tracefile);
904 }
905}
906
907static void
908opentrace(void)
909{
910 char s[100];
911#ifdef O_APPEND
912 int flags;
913#endif
914
915 if (debug != 1) {
916 if (tracefile)
917 fflush(tracefile);
918 /* leave open because libedit might be using it */
919 return;
920 }
921 strcpy(s, "./trace");
922 if (tracefile) {
923 if (!freopen(s, "a", tracefile)) {
924 fprintf(stderr, "Can't re-open %s\n", s);
925 debug = 0;
926 return;
927 }
928 } else {
929 tracefile = fopen(s, "a");
930 if (tracefile == NULL) {
931 fprintf(stderr, "Can't open %s\n", s);
932 debug = 0;
933 return;
934 }
935 }
936#ifdef O_APPEND
Denis Vlasenkod37f2222007-08-19 13:42:08 +0000937 flags = fcntl(fileno(tracefile), F_GETFL);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000938 if (flags >= 0)
939 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
940#endif
941 setlinebuf(tracefile);
942 fputs("\nTracing started.\n", tracefile);
943}
944
945static void
946indent(int amount, char *pfx, FILE *fp)
947{
948 int i;
949
950 for (i = 0; i < amount; i++) {
951 if (pfx && i == amount - 1)
952 fputs(pfx, fp);
953 putc('\t', fp);
954 }
955}
956
957/* little circular references here... */
958static void shtree(union node *n, int ind, char *pfx, FILE *fp);
959
960static void
961sharg(union node *arg, FILE *fp)
962{
963 char *p;
964 struct nodelist *bqlist;
Denys Vlasenkocd716832009-11-28 22:14:02 +0100965 unsigned char subtype;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000966
967 if (arg->type != NARG) {
968 out1fmt("<node type %d>\n", arg->type);
969 abort();
970 }
971 bqlist = arg->narg.backquote;
972 for (p = arg->narg.text; *p; p++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +0100973 switch ((unsigned char)*p) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000974 case CTLESC:
Dan Fandrich77d48722010-09-07 23:38:28 -0700975 p++;
976 putc(*p, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000977 break;
978 case CTLVAR:
979 putc('$', fp);
980 putc('{', fp);
981 subtype = *++p;
982 if (subtype == VSLENGTH)
983 putc('#', fp);
984
Dan Fandrich77d48722010-09-07 23:38:28 -0700985 while (*p != '=') {
986 putc(*p, fp);
987 p++;
988 }
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +0000989
990 if (subtype & VSNUL)
991 putc(':', fp);
992
993 switch (subtype & VSTYPE) {
994 case VSNORMAL:
995 putc('}', fp);
996 break;
997 case VSMINUS:
998 putc('-', fp);
999 break;
1000 case VSPLUS:
1001 putc('+', fp);
1002 break;
1003 case VSQUESTION:
1004 putc('?', fp);
1005 break;
1006 case VSASSIGN:
1007 putc('=', fp);
1008 break;
1009 case VSTRIMLEFT:
1010 putc('#', fp);
1011 break;
1012 case VSTRIMLEFTMAX:
1013 putc('#', fp);
1014 putc('#', fp);
1015 break;
1016 case VSTRIMRIGHT:
1017 putc('%', fp);
1018 break;
1019 case VSTRIMRIGHTMAX:
1020 putc('%', fp);
1021 putc('%', fp);
1022 break;
1023 case VSLENGTH:
1024 break;
1025 default:
1026 out1fmt("<subtype %d>", subtype);
1027 }
1028 break;
1029 case CTLENDVAR:
1030 putc('}', fp);
1031 break;
1032 case CTLBACKQ:
1033 case CTLBACKQ|CTLQUOTE:
1034 putc('$', fp);
1035 putc('(', fp);
1036 shtree(bqlist->n, -1, NULL, fp);
1037 putc(')', fp);
1038 break;
1039 default:
1040 putc(*p, fp);
1041 break;
1042 }
1043 }
1044}
1045
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02001046static void
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001047shcmd(union node *cmd, FILE *fp)
1048{
1049 union node *np;
1050 int first;
1051 const char *s;
1052 int dftfd;
1053
1054 first = 1;
1055 for (np = cmd->ncmd.args; np; np = np->narg.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001056 if (!first)
1057 putc(' ', fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001058 sharg(np, fp);
1059 first = 0;
1060 }
1061 for (np = cmd->ncmd.redirect; np; np = np->nfile.next) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001062 if (!first)
1063 putc(' ', fp);
1064 dftfd = 0;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001065 switch (np->nfile.type) {
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001066 case NTO: s = ">>"+1; dftfd = 1; break;
1067 case NCLOBBER: s = ">|"; dftfd = 1; break;
1068 case NAPPEND: s = ">>"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001069#if ENABLE_ASH_BASH_COMPAT
1070 case NTO2:
1071#endif
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001072 case NTOFD: s = ">&"; dftfd = 1; break;
Denis Vlasenko559691a2008-10-05 18:39:31 +00001073 case NFROM: s = "<"; break;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00001074 case NFROMFD: s = "<&"; break;
1075 case NFROMTO: s = "<>"; break;
1076 default: s = "*error*"; break;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001077 }
1078 if (np->nfile.fd != dftfd)
1079 fprintf(fp, "%d", np->nfile.fd);
1080 fputs(s, fp);
1081 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
1082 fprintf(fp, "%d", np->ndup.dupfd);
1083 } else {
1084 sharg(np->nfile.fname, fp);
1085 }
1086 first = 0;
1087 }
1088}
1089
1090static void
1091shtree(union node *n, int ind, char *pfx, FILE *fp)
1092{
1093 struct nodelist *lp;
1094 const char *s;
1095
1096 if (n == NULL)
1097 return;
1098
1099 indent(ind, pfx, fp);
Denys Vlasenko86e83ec2009-07-23 22:07:07 +02001100
1101 if (n == NODE_EOF) {
1102 fputs("<EOF>", fp);
1103 return;
1104 }
1105
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001106 switch (n->type) {
1107 case NSEMI:
1108 s = "; ";
1109 goto binop;
1110 case NAND:
1111 s = " && ";
1112 goto binop;
1113 case NOR:
1114 s = " || ";
1115 binop:
1116 shtree(n->nbinary.ch1, ind, NULL, fp);
1117 /* if (ind < 0) */
1118 fputs(s, fp);
1119 shtree(n->nbinary.ch2, ind, NULL, fp);
1120 break;
1121 case NCMD:
1122 shcmd(n, fp);
1123 if (ind >= 0)
1124 putc('\n', fp);
1125 break;
1126 case NPIPE:
1127 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02001128 shtree(lp->n, 0, NULL, fp);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001129 if (lp->next)
1130 fputs(" | ", fp);
1131 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00001132 if (n->npipe.pipe_backgnd)
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001133 fputs(" &", fp);
1134 if (ind >= 0)
1135 putc('\n', fp);
1136 break;
1137 default:
1138 fprintf(fp, "<node type %d>", n->type);
1139 if (ind >= 0)
1140 putc('\n', fp);
1141 break;
1142 }
1143}
1144
1145static void
1146showtree(union node *n)
1147{
1148 trace_puts("showtree called\n");
Denys Vlasenko883cea42009-07-11 15:31:59 +02001149 shtree(n, 1, NULL, stderr);
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001150}
1151
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001152#endif /* DEBUG */
1153
1154
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001155/* ============ Parser data */
1156
1157/*
Denis Vlasenkob012b102007-02-19 22:43:01 +00001158 * ash_vmsg() needs parsefile->fd, hence parsefile definition is moved up.
1159 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001160struct strlist {
1161 struct strlist *next;
1162 char *text;
1163};
1164
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001165struct alias;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00001166
Denis Vlasenkob012b102007-02-19 22:43:01 +00001167struct strpush {
1168 struct strpush *prev; /* preceding string on stack */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001169 char *prev_string;
1170 int prev_left_in_line;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001171#if ENABLE_ASH_ALIAS
1172 struct alias *ap; /* if push was associated with an alias */
1173#endif
1174 char *string; /* remember the string since it may change */
1175};
1176
1177struct parsefile {
1178 struct parsefile *prev; /* preceding file on stack */
1179 int linno; /* current line */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001180 int pf_fd; /* file descriptor (or -1 if string) */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00001181 int left_in_line; /* number of chars left in this line */
1182 int left_in_buffer; /* number of chars left in this buffer past the line */
1183 char *next_to_pgetc; /* next char in buffer */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001184 char *buf; /* input buffer */
1185 struct strpush *strpush; /* for pushing strings at this level */
1186 struct strpush basestrpush; /* so pushing one is fast */
1187};
1188
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001189static struct parsefile basepf; /* top level input file */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00001190static struct parsefile *g_parsefile = &basepf; /* current input file */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001191static int startlinno; /* line # where last token started */
1192static char *commandname; /* currently executing command */
1193static struct strlist *cmdenviron; /* environment for builtin command */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001194static uint8_t exitstatus; /* exit status of last command */
Denis Vlasenkob012b102007-02-19 22:43:01 +00001195
1196
1197/* ============ Message printing */
1198
1199static void
1200ash_vmsg(const char *msg, va_list ap)
1201{
1202 fprintf(stderr, "%s: ", arg0);
1203 if (commandname) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001204 if (strcmp(arg0, commandname))
1205 fprintf(stderr, "%s: ", commandname);
Denys Vlasenko79b3d422010-06-03 04:29:08 +02001206 if (!iflag || g_parsefile->pf_fd > 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001207 fprintf(stderr, "line %d: ", startlinno);
Eric Andersenc470f442003-07-28 09:56:35 +00001208 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00001209 vfprintf(stderr, msg, ap);
1210 outcslow('\n', stderr);
Eric Andersenc470f442003-07-28 09:56:35 +00001211}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001212
1213/*
1214 * Exverror is called to raise the error exception. If the second argument
1215 * is not NULL then error prints an error message using printf style
1216 * formatting. It then raises the error exception.
1217 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001218static void ash_vmsg_and_raise(int, const char *, va_list) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001219static void
1220ash_vmsg_and_raise(int cond, const char *msg, va_list ap)
Eric Andersenc470f442003-07-28 09:56:35 +00001221{
Denis Vlasenkob012b102007-02-19 22:43:01 +00001222#if DEBUG
1223 if (msg) {
1224 TRACE(("ash_vmsg_and_raise(%d, \"", cond));
1225 TRACEV((msg, ap));
1226 TRACE(("\") pid=%d\n", getpid()));
1227 } else
1228 TRACE(("ash_vmsg_and_raise(%d, NULL) pid=%d\n", cond, getpid()));
1229 if (msg)
1230#endif
1231 ash_vmsg(msg, ap);
1232
1233 flush_stdout_stderr();
1234 raise_exception(cond);
1235 /* NOTREACHED */
Eric Andersenc470f442003-07-28 09:56:35 +00001236}
Denis Vlasenkob012b102007-02-19 22:43:01 +00001237
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001238static void ash_msg_and_raise_error(const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001239static void
1240ash_msg_and_raise_error(const char *msg, ...)
1241{
1242 va_list ap;
1243
1244 va_start(ap, msg);
1245 ash_vmsg_and_raise(EXERROR, msg, ap);
1246 /* NOTREACHED */
1247 va_end(ap);
1248}
1249
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00001250static void raise_error_syntax(const char *) NORETURN;
1251static void
1252raise_error_syntax(const char *msg)
1253{
1254 ash_msg_and_raise_error("syntax error: %s", msg);
1255 /* NOTREACHED */
1256}
1257
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001258static void ash_msg_and_raise(int, const char *, ...) NORETURN;
Denis Vlasenkob012b102007-02-19 22:43:01 +00001259static void
1260ash_msg_and_raise(int cond, const char *msg, ...)
1261{
1262 va_list ap;
1263
1264 va_start(ap, msg);
1265 ash_vmsg_and_raise(cond, msg, ap);
1266 /* NOTREACHED */
1267 va_end(ap);
1268}
1269
1270/*
1271 * error/warning routines for external builtins
1272 */
1273static void
1274ash_msg(const char *fmt, ...)
1275{
1276 va_list ap;
1277
1278 va_start(ap, fmt);
1279 ash_vmsg(fmt, ap);
1280 va_end(ap);
1281}
1282
1283/*
1284 * Return a string describing an error. The returned string may be a
1285 * pointer to a static buffer that will be overwritten on the next call.
1286 * Action describes the operation that got the error.
1287 */
1288static const char *
1289errmsg(int e, const char *em)
1290{
1291 if (e == ENOENT || e == ENOTDIR) {
1292 return em;
1293 }
1294 return strerror(e);
1295}
1296
1297
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001298/* ============ Memory allocation */
1299
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001300#if 0
1301/* I consider these wrappers nearly useless:
1302 * ok, they return you to nearest exception handler, but
1303 * how much memory do you leak in the process, making
1304 * memory starvation worse?
1305 */
1306static void *
1307ckrealloc(void * p, size_t nbytes)
1308{
1309 p = realloc(p, nbytes);
1310 if (!p)
1311 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1312 return p;
1313}
1314
1315static void *
1316ckmalloc(size_t nbytes)
1317{
1318 return ckrealloc(NULL, nbytes);
1319}
1320
1321static void *
1322ckzalloc(size_t nbytes)
1323{
1324 return memset(ckmalloc(nbytes), 0, nbytes);
1325}
1326
1327static char *
1328ckstrdup(const char *s)
1329{
1330 char *p = strdup(s);
1331 if (!p)
1332 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1333 return p;
1334}
1335#else
1336/* Using bbox equivalents. They exit if out of memory */
1337# define ckrealloc xrealloc
1338# define ckmalloc xmalloc
1339# define ckzalloc xzalloc
1340# define ckstrdup xstrdup
1341#endif
1342
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001343/*
1344 * It appears that grabstackstr() will barf with such alignments
1345 * because stalloc() will return a string allocated in a new stackblock.
1346 */
1347#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)
1348enum {
1349 /* Most machines require the value returned from malloc to be aligned
1350 * in some way. The following macro will get this right
1351 * on many machines. */
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02001352 SHELL_SIZE = sizeof(union { int i; char *cp; double d; }) - 1,
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001353 /* Minimum size of a block */
Denis Vlasenko01631112007-12-16 17:20:38 +00001354 MINSIZE = SHELL_ALIGN(504),
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001355};
1356
1357struct stack_block {
1358 struct stack_block *prev;
1359 char space[MINSIZE];
1360};
1361
1362struct stackmark {
1363 struct stack_block *stackp;
1364 char *stacknxt;
1365 size_t stacknleft;
1366 struct stackmark *marknext;
1367};
1368
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001369
Denis Vlasenko01631112007-12-16 17:20:38 +00001370struct globals_memstack {
1371 struct stack_block *g_stackp; // = &stackbase;
1372 struct stackmark *markp;
1373 char *g_stacknxt; // = stackbase.space;
1374 char *sstrend; // = stackbase.space + MINSIZE;
1375 size_t g_stacknleft; // = MINSIZE;
1376 int herefd; // = -1;
1377 struct stack_block stackbase;
1378};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001379extern struct globals_memstack *const ash_ptr_to_globals_memstack;
1380#define G_memstack (*ash_ptr_to_globals_memstack)
Denis Vlasenko01631112007-12-16 17:20:38 +00001381#define g_stackp (G_memstack.g_stackp )
1382#define markp (G_memstack.markp )
1383#define g_stacknxt (G_memstack.g_stacknxt )
1384#define sstrend (G_memstack.sstrend )
1385#define g_stacknleft (G_memstack.g_stacknleft)
1386#define herefd (G_memstack.herefd )
1387#define stackbase (G_memstack.stackbase )
1388#define INIT_G_memstack() do { \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001389 (*(struct globals_memstack**)&ash_ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \
1390 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001391 g_stackp = &stackbase; \
1392 g_stacknxt = stackbase.space; \
1393 g_stacknleft = MINSIZE; \
1394 sstrend = stackbase.space + MINSIZE; \
1395 herefd = -1; \
1396} while (0)
1397
Denys Vlasenkoe7670ff2009-10-11 00:45:25 +02001398
Denis Vlasenko01631112007-12-16 17:20:38 +00001399#define stackblock() ((void *)g_stacknxt)
1400#define stackblocksize() g_stacknleft
1401
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001402/*
1403 * Parse trees for commands are allocated in lifo order, so we use a stack
1404 * to make this more efficient, and also to avoid all sorts of exception
1405 * handling code to handle interrupts in the middle of a parse.
1406 *
1407 * The size 504 was chosen because the Ultrix malloc handles that size
1408 * well.
1409 */
1410static void *
1411stalloc(size_t nbytes)
1412{
1413 char *p;
1414 size_t aligned;
1415
1416 aligned = SHELL_ALIGN(nbytes);
Denis Vlasenko01631112007-12-16 17:20:38 +00001417 if (aligned > g_stacknleft) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001418 size_t len;
1419 size_t blocksize;
1420 struct stack_block *sp;
1421
1422 blocksize = aligned;
1423 if (blocksize < MINSIZE)
1424 blocksize = MINSIZE;
1425 len = sizeof(struct stack_block) - MINSIZE + blocksize;
1426 if (len < blocksize)
1427 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1428 INT_OFF;
1429 sp = ckmalloc(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001430 sp->prev = g_stackp;
1431 g_stacknxt = sp->space;
1432 g_stacknleft = blocksize;
1433 sstrend = g_stacknxt + blocksize;
1434 g_stackp = sp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001435 INT_ON;
1436 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001437 p = g_stacknxt;
1438 g_stacknxt += aligned;
1439 g_stacknleft -= aligned;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001440 return p;
1441}
1442
Denis Vlasenko597906c2008-02-20 16:38:54 +00001443static void *
1444stzalloc(size_t nbytes)
1445{
1446 return memset(stalloc(nbytes), 0, nbytes);
1447}
1448
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001449static void
1450stunalloc(void *p)
1451{
1452#if DEBUG
Denis Vlasenko01631112007-12-16 17:20:38 +00001453 if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) {
Bernhard Reutner-Fischer5e25ddb2008-05-19 09:48:17 +00001454 write(STDERR_FILENO, "stunalloc\n", 10);
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001455 abort();
1456 }
1457#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001458 g_stacknleft += g_stacknxt - (char *)p;
1459 g_stacknxt = p;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001460}
1461
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001462/*
1463 * Like strdup but works with the ash stack.
1464 */
1465static char *
1466ststrdup(const char *p)
1467{
1468 size_t len = strlen(p) + 1;
1469 return memcpy(stalloc(len), p, len);
1470}
1471
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001472static void
1473setstackmark(struct stackmark *mark)
1474{
Denis Vlasenko01631112007-12-16 17:20:38 +00001475 mark->stackp = g_stackp;
1476 mark->stacknxt = g_stacknxt;
1477 mark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001478 mark->marknext = markp;
1479 markp = mark;
1480}
1481
1482static void
1483popstackmark(struct stackmark *mark)
1484{
1485 struct stack_block *sp;
1486
Denis Vlasenko93ebd4f2007-03-13 20:55:36 +00001487 if (!mark->stackp)
1488 return;
1489
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001490 INT_OFF;
1491 markp = mark->marknext;
Denis Vlasenko01631112007-12-16 17:20:38 +00001492 while (g_stackp != mark->stackp) {
1493 sp = g_stackp;
1494 g_stackp = sp->prev;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001495 free(sp);
1496 }
Denis Vlasenko01631112007-12-16 17:20:38 +00001497 g_stacknxt = mark->stacknxt;
1498 g_stacknleft = mark->stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001499 sstrend = mark->stacknxt + mark->stacknleft;
1500 INT_ON;
1501}
1502
1503/*
1504 * When the parser reads in a string, it wants to stick the string on the
1505 * stack and only adjust the stack pointer when it knows how big the
1506 * string is. Stackblock (defined in stack.h) returns a pointer to a block
1507 * of space on top of the stack and stackblocklen returns the length of
1508 * this block. Growstackblock will grow this space by at least one byte,
1509 * possibly moving it (like realloc). Grabstackblock actually allocates the
1510 * part of the block that has been used.
1511 */
1512static void
1513growstackblock(void)
1514{
1515 size_t newlen;
1516
Denis Vlasenko01631112007-12-16 17:20:38 +00001517 newlen = g_stacknleft * 2;
1518 if (newlen < g_stacknleft)
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001519 ash_msg_and_raise_error(bb_msg_memory_exhausted);
1520 if (newlen < 128)
1521 newlen += 128;
1522
Denis Vlasenko01631112007-12-16 17:20:38 +00001523 if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001524 struct stack_block *oldstackp;
1525 struct stackmark *xmark;
1526 struct stack_block *sp;
1527 struct stack_block *prevstackp;
1528 size_t grosslen;
1529
1530 INT_OFF;
Denis Vlasenko01631112007-12-16 17:20:38 +00001531 oldstackp = g_stackp;
1532 sp = g_stackp;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001533 prevstackp = sp->prev;
1534 grosslen = newlen + sizeof(struct stack_block) - MINSIZE;
1535 sp = ckrealloc(sp, grosslen);
1536 sp->prev = prevstackp;
Denis Vlasenko01631112007-12-16 17:20:38 +00001537 g_stackp = sp;
1538 g_stacknxt = sp->space;
1539 g_stacknleft = newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001540 sstrend = sp->space + newlen;
1541
1542 /*
1543 * Stack marks pointing to the start of the old block
1544 * must be relocated to point to the new block
1545 */
1546 xmark = markp;
1547 while (xmark != NULL && xmark->stackp == oldstackp) {
Denis Vlasenko01631112007-12-16 17:20:38 +00001548 xmark->stackp = g_stackp;
1549 xmark->stacknxt = g_stacknxt;
1550 xmark->stacknleft = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001551 xmark = xmark->marknext;
1552 }
1553 INT_ON;
1554 } else {
Denis Vlasenko01631112007-12-16 17:20:38 +00001555 char *oldspace = g_stacknxt;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001556 size_t oldlen = g_stacknleft;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001557 char *p = stalloc(newlen);
1558
1559 /* free the space we just allocated */
Denis Vlasenko01631112007-12-16 17:20:38 +00001560 g_stacknxt = memcpy(p, oldspace, oldlen);
1561 g_stacknleft += newlen;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001562 }
1563}
1564
1565static void
1566grabstackblock(size_t len)
1567{
1568 len = SHELL_ALIGN(len);
Denis Vlasenko01631112007-12-16 17:20:38 +00001569 g_stacknxt += len;
1570 g_stacknleft -= len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001571}
1572
1573/*
1574 * The following routines are somewhat easier to use than the above.
1575 * The user declares a variable of type STACKSTR, which may be declared
1576 * to be a register. The macro STARTSTACKSTR initializes things. Then
1577 * the user uses the macro STPUTC to add characters to the string. In
1578 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
1579 * grown as necessary. When the user is done, she can just leave the
1580 * string there and refer to it using stackblock(). Or she can allocate
1581 * the space for it using grabstackstr(). If it is necessary to allow
1582 * someone else to use the stack temporarily and then continue to grow
1583 * the string, the user should use grabstack to allocate the space, and
1584 * then call ungrabstr(p) to return to the previous mode of operation.
1585 *
1586 * USTPUTC is like STPUTC except that it doesn't check for overflow.
1587 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
1588 * is space for at least one character.
1589 */
1590static void *
1591growstackstr(void)
1592{
1593 size_t len = stackblocksize();
1594 if (herefd >= 0 && len >= 1024) {
1595 full_write(herefd, stackblock(), len);
1596 return stackblock();
1597 }
1598 growstackblock();
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001599 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001600}
1601
1602/*
1603 * Called from CHECKSTRSPACE.
1604 */
1605static char *
1606makestrspace(size_t newlen, char *p)
1607{
Denis Vlasenko01631112007-12-16 17:20:38 +00001608 size_t len = p - g_stacknxt;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001609 size_t size = stackblocksize();
1610
1611 for (;;) {
1612 size_t nleft;
1613
1614 size = stackblocksize();
1615 nleft = size - len;
1616 if (nleft >= newlen)
1617 break;
1618 growstackblock();
1619 }
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001620 return (char *)stackblock() + len;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001621}
1622
1623static char *
1624stack_nputstr(const char *s, size_t n, char *p)
1625{
1626 p = makestrspace(n, p);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001627 p = (char *)memcpy(p, s, n) + n;
Denis Vlasenko0c032a42007-02-23 01:03:40 +00001628 return p;
1629}
1630
1631static char *
1632stack_putstr(const char *s, char *p)
1633{
1634 return stack_nputstr(s, strlen(s), p);
1635}
1636
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001637static char *
1638_STPUTC(int c, char *p)
1639{
1640 if (p == sstrend)
1641 p = growstackstr();
1642 *p++ = c;
1643 return p;
1644}
1645
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001646#define STARTSTACKSTR(p) ((p) = stackblock())
1647#define STPUTC(c, p) ((p) = _STPUTC((c), (p)))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001648#define CHECKSTRSPACE(n, p) do { \
1649 char *q = (p); \
1650 size_t l = (n); \
1651 size_t m = sstrend - q; \
1652 if (l > m) \
1653 (p) = makestrspace(l, q); \
1654} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001655#define USTPUTC(c, p) (*(p)++ = (c))
Denis Vlasenko843cbd52008-06-27 00:23:18 +00001656#define STACKSTRNUL(p) do { \
1657 if ((p) == sstrend) \
1658 (p) = growstackstr(); \
1659 *(p) = '\0'; \
1660} while (0)
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001661#define STUNPUTC(p) (--(p))
1662#define STTOPC(p) ((p)[-1])
1663#define STADJUST(amount, p) ((p) += (amount))
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001664
1665#define grabstackstr(p) stalloc((char *)(p) - (char *)stackblock())
Denis Vlasenkoef527f52008-06-23 01:52:30 +00001666#define ungrabstackstr(s, p) stunalloc(s)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001667#define stackstrend() ((void *)sstrend)
1668
1669
1670/* ============ String helpers */
1671
1672/*
1673 * prefix -- see if pfx is a prefix of string.
1674 */
1675static char *
1676prefix(const char *string, const char *pfx)
1677{
1678 while (*pfx) {
1679 if (*pfx++ != *string++)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00001680 return NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001681 }
1682 return (char *) string;
1683}
1684
1685/*
1686 * Check for a valid number. This should be elsewhere.
1687 */
1688static int
1689is_number(const char *p)
1690{
1691 do {
1692 if (!isdigit(*p))
1693 return 0;
1694 } while (*++p != '\0');
1695 return 1;
1696}
1697
1698/*
1699 * Convert a string of digits to an integer, printing an error message on
1700 * failure.
1701 */
1702static int
1703number(const char *s)
1704{
1705 if (!is_number(s))
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02001706 ash_msg_and_raise_error(msg_illnum, s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001707 return atoi(s);
1708}
1709
1710/*
1711 * Produce a possibly single quoted string suitable as input to the shell.
1712 * The return string is allocated on the stack.
1713 */
1714static char *
1715single_quote(const char *s)
1716{
1717 char *p;
1718
1719 STARTSTACKSTR(p);
1720
1721 do {
1722 char *q;
1723 size_t len;
1724
1725 len = strchrnul(s, '\'') - s;
1726
1727 q = p = makestrspace(len + 3, p);
1728
1729 *q++ = '\'';
Denis Vlasenko29eb3592008-05-18 14:06:08 +00001730 q = (char *)memcpy(q, s, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001731 *q++ = '\'';
1732 s += len;
1733
1734 STADJUST(q - p, p);
1735
Denys Vlasenkocd716832009-11-28 22:14:02 +01001736 if (*s != '\'')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001737 break;
Denys Vlasenkocd716832009-11-28 22:14:02 +01001738 len = 0;
1739 do len++; while (*++s == '\'');
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001740
1741 q = p = makestrspace(len + 3, p);
1742
1743 *q++ = '"';
Denys Vlasenkocd716832009-11-28 22:14:02 +01001744 q = (char *)memcpy(q, s - len, len) + len;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001745 *q++ = '"';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001746
1747 STADJUST(q - p, p);
1748 } while (*s);
1749
Denys Vlasenkocd716832009-11-28 22:14:02 +01001750 USTPUTC('\0', p);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001751
1752 return stackblock();
1753}
1754
1755
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00001756/* ============ nextopt */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001757
1758static char **argptr; /* argument list for builtin commands */
1759static char *optionarg; /* set by nextopt (like getopt) */
1760static char *optptr; /* used by nextopt */
1761
1762/*
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001763 * XXX - should get rid of. Have all builtins use getopt(3).
1764 * The library getopt must have the BSD extension static variable
1765 * "optreset", otherwise it can't be used within the shell safely.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001766 *
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001767 * Standard option processing (a la getopt) for builtin routines.
1768 * The only argument that is passed to nextopt is the option string;
1769 * the other arguments are unnecessary. It returns the character,
1770 * or '\0' on end of input.
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001771 */
1772static int
1773nextopt(const char *optstring)
1774{
1775 char *p;
1776 const char *q;
1777 char c;
1778
1779 p = optptr;
1780 if (p == NULL || *p == '\0') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001781 /* We ate entire "-param", take next one */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001782 p = *argptr;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001783 if (p == NULL)
1784 return '\0';
1785 if (*p != '-')
1786 return '\0';
1787 if (*++p == '\0') /* just "-" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001788 return '\0';
1789 argptr++;
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001790 if (LONE_DASH(p)) /* "--" ? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001791 return '\0';
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001792 /* p => next "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001793 }
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001794 /* p => some option char in the middle of a "-param" */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001795 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00001796 for (q = optstring; *q != c;) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001797 if (*q == '\0')
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00001798 ash_msg_and_raise_error("illegal option -%c", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001799 if (*++q == ':')
1800 q++;
1801 }
1802 if (*++q == ':') {
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00001803 if (*p == '\0') {
1804 p = *argptr++;
1805 if (p == NULL)
1806 ash_msg_and_raise_error("no arg for -%c option", c);
1807 }
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001808 optionarg = p;
1809 p = NULL;
1810 }
1811 optptr = p;
1812 return c;
1813}
1814
1815
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001816/* ============ Shell variables */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001817
Denis Vlasenko01631112007-12-16 17:20:38 +00001818/*
1819 * The parsefile structure pointed to by the global variable parsefile
1820 * contains information about the current file being read.
1821 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001822struct shparam {
1823 int nparam; /* # of positional parameters (without $0) */
1824#if ENABLE_ASH_GETOPTS
1825 int optind; /* next parameter to be processed by getopts */
1826 int optoff; /* used by getopts */
1827#endif
1828 unsigned char malloced; /* if parameter list dynamically allocated */
1829 char **p; /* parameter list */
1830};
1831
1832/*
1833 * Free the list of positional parameters.
1834 */
1835static void
1836freeparam(volatile struct shparam *param)
1837{
Denis Vlasenko01631112007-12-16 17:20:38 +00001838 if (param->malloced) {
Denis Vlasenko3177ba02008-07-13 20:39:23 +00001839 char **ap, **ap1;
1840 ap = ap1 = param->p;
1841 while (*ap)
1842 free(*ap++);
1843 free(ap1);
Denis Vlasenko01631112007-12-16 17:20:38 +00001844 }
1845}
1846
1847#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001848static void FAST_FUNC getoptsreset(const char *value);
Denis Vlasenko01631112007-12-16 17:20:38 +00001849#endif
1850
1851struct var {
1852 struct var *next; /* next entry in hash list */
1853 int flags; /* flags are defined above */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001854 const char *var_text; /* name=value */
1855 void (*var_func)(const char *) FAST_FUNC; /* function to be called when */
Denis Vlasenko01631112007-12-16 17:20:38 +00001856 /* the variable gets set/unset */
1857};
1858
1859struct localvar {
1860 struct localvar *next; /* next local variable in list */
1861 struct var *vp; /* the variable that was made local */
1862 int flags; /* saved flags */
1863 const char *text; /* saved text */
1864};
1865
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001866/* flags */
1867#define VEXPORT 0x01 /* variable is exported */
1868#define VREADONLY 0x02 /* variable cannot be modified */
1869#define VSTRFIXED 0x04 /* variable struct is statically allocated */
1870#define VTEXTFIXED 0x08 /* text is statically allocated */
1871#define VSTACK 0x10 /* text is allocated on the stack */
1872#define VUNSET 0x20 /* the variable is not set */
1873#define VNOFUNC 0x40 /* don't call the callback function */
1874#define VNOSET 0x80 /* do not set variable - just readonly test */
1875#define VNOSAVE 0x100 /* when text is on the heap before setvareq */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00001876#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00001877# define VDYNAMIC 0x200 /* dynamic variable */
1878#else
1879# define VDYNAMIC 0
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001880#endif
1881
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001882
Denis Vlasenko01631112007-12-16 17:20:38 +00001883/* Need to be before varinit_data[] */
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001884#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001885static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001886change_lc_all(const char *value)
1887{
1888 if (value && *value != '\0')
1889 setlocale(LC_ALL, value);
1890}
Denys Vlasenko2634bf32009-06-09 18:40:07 +02001891static void FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00001892change_lc_ctype(const char *value)
1893{
1894 if (value && *value != '\0')
1895 setlocale(LC_CTYPE, value);
1896}
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00001897#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001898#if ENABLE_ASH_MAIL
1899static void chkmail(void);
Denys Vlasenko8c52f802011-02-04 17:36:21 +01001900static void changemail(const char *var_value) FAST_FUNC;
1901#else
1902# define chkmail() ((void)0)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001903#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001904static void changepath(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001905#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02001906static void change_random(const char *) FAST_FUNC;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001907#endif
1908
Denis Vlasenko01631112007-12-16 17:20:38 +00001909static const struct {
1910 int flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001911 const char *var_text;
1912 void (*var_func)(const char *) FAST_FUNC;
Denis Vlasenko01631112007-12-16 17:20:38 +00001913} varinit_data[] = {
Denys Vlasenko566a3132012-07-07 21:40:35 +02001914 /*
1915 * Note: VEXPORT would not work correctly here for NOFORK applets:
1916 * some environment strings may be constant.
1917 */
Denis Vlasenko01631112007-12-16 17:20:38 +00001918 { VSTRFIXED|VTEXTFIXED , defifsvar , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001919#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001920 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail },
1921 { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001922#endif
Denis Vlasenko01631112007-12-16 17:20:38 +00001923 { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath },
1924 { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL },
1925 { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL },
1926 { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001927#if ENABLE_ASH_GETOPTS
Denis Vlasenko01631112007-12-16 17:20:38 +00001928 { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001929#endif
1930#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001931 { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM", change_random },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001932#endif
1933#if ENABLE_LOCALE_SUPPORT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001934 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL" , change_lc_all },
1935 { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE" , change_lc_ctype },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001936#endif
1937#if ENABLE_FEATURE_EDITING_SAVEHISTORY
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001938 { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE" , NULL },
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001939#endif
1940};
1941
Denis Vlasenko0b769642008-07-24 07:54:57 +00001942struct redirtab;
Denis Vlasenko01631112007-12-16 17:20:38 +00001943
1944struct globals_var {
1945 struct shparam shellparam; /* $@ current positional parameters */
1946 struct redirtab *redirlist;
1947 int g_nullredirs;
1948 int preverrout_fd; /* save fd2 before print debug if xflag is set. */
1949 struct var *vartab[VTABSIZE];
1950 struct var varinit[ARRAY_SIZE(varinit_data)];
1951};
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001952extern struct globals_var *const ash_ptr_to_globals_var;
1953#define G_var (*ash_ptr_to_globals_var)
Denis Vlasenko01631112007-12-16 17:20:38 +00001954#define shellparam (G_var.shellparam )
Denis Vlasenko0b769642008-07-24 07:54:57 +00001955//#define redirlist (G_var.redirlist )
Denis Vlasenko01631112007-12-16 17:20:38 +00001956#define g_nullredirs (G_var.g_nullredirs )
1957#define preverrout_fd (G_var.preverrout_fd)
1958#define vartab (G_var.vartab )
1959#define varinit (G_var.varinit )
1960#define INIT_G_var() do { \
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00001961 unsigned i; \
Denis Vlasenko574f2f42008-02-27 18:41:59 +00001962 (*(struct globals_var**)&ash_ptr_to_globals_var) = xzalloc(sizeof(G_var)); \
1963 barrier(); \
Denis Vlasenko01631112007-12-16 17:20:38 +00001964 for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001965 varinit[i].flags = varinit_data[i].flags; \
1966 varinit[i].var_text = varinit_data[i].var_text; \
1967 varinit[i].var_func = varinit_data[i].var_func; \
Denis Vlasenko01631112007-12-16 17:20:38 +00001968 } \
1969} while (0)
1970
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001971#define vifs varinit[0]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001972#if ENABLE_ASH_MAIL
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001973# define vmail (&vifs)[1]
1974# define vmpath (&vmail)[1]
1975# define vpath (&vmpath)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001976#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001977# define vpath (&vifs)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001978#endif
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001979#define vps1 (&vpath)[1]
1980#define vps2 (&vps1)[1]
1981#define vps4 (&vps2)[1]
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001982#if ENABLE_ASH_GETOPTS
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001983# define voptind (&vps4)[1]
1984# if ENABLE_ASH_RANDOM_SUPPORT
1985# define vrandom (&voptind)[1]
1986# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001987#else
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00001988# if ENABLE_ASH_RANDOM_SUPPORT
1989# define vrandom (&vps4)[1]
1990# endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001991#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001992
1993/*
1994 * The following macros access the values of the above variables.
1995 * They have to skip over the name. They return the null string
1996 * for unset variables.
1997 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02001998#define ifsval() (vifs.var_text + 4)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00001999#define ifsset() ((vifs.flags & VUNSET) == 0)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002000#if ENABLE_ASH_MAIL
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002001# define mailval() (vmail.var_text + 5)
2002# define mpathval() (vmpath.var_text + 9)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002003# define mpathset() ((vmpath.flags & VUNSET) == 0)
2004#endif
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002005#define pathval() (vpath.var_text + 5)
2006#define ps1val() (vps1.var_text + 4)
2007#define ps2val() (vps2.var_text + 4)
2008#define ps4val() (vps4.var_text + 4)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002009#if ENABLE_ASH_GETOPTS
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002010# define optindval() (voptind.var_text + 7)
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00002011#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002012
Denis Vlasenko01631112007-12-16 17:20:38 +00002013#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002014static void FAST_FUNC
Denis Vlasenko01631112007-12-16 17:20:38 +00002015getoptsreset(const char *value)
2016{
2017 shellparam.optind = number(value);
2018 shellparam.optoff = -1;
2019}
2020#endif
2021
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002022/*
2023 * Compares two strings up to the first = or '\0'. The first
2024 * string must be terminated by '='; the second may be terminated by
2025 * either '=' or '\0'.
2026 */
2027static int
2028varcmp(const char *p, const char *q)
2029{
2030 int c, d;
2031
2032 while ((c = *p) == (d = *q)) {
2033 if (!c || c == '=')
2034 goto out;
2035 p++;
2036 q++;
2037 }
2038 if (c == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002039 c = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002040 if (d == '=')
Denis Vlasenko9650f362007-02-23 01:04:37 +00002041 d = '\0';
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002042 out:
2043 return c - d;
2044}
2045
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002046/*
2047 * Find the appropriate entry in the hash table from the name.
2048 */
2049static struct var **
2050hashvar(const char *p)
2051{
2052 unsigned hashval;
2053
2054 hashval = ((unsigned char) *p) << 4;
2055 while (*p && *p != '=')
2056 hashval += (unsigned char) *p++;
2057 return &vartab[hashval % VTABSIZE];
2058}
2059
2060static int
2061vpcmp(const void *a, const void *b)
2062{
2063 return varcmp(*(const char **)a, *(const char **)b);
2064}
2065
2066/*
2067 * This routine initializes the builtin variables.
2068 */
2069static void
2070initvar(void)
2071{
2072 struct var *vp;
2073 struct var *end;
2074 struct var **vpp;
2075
2076 /*
2077 * PS1 depends on uid
2078 */
2079#if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002080 vps1.var_text = "PS1=\\w \\$ ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002081#else
2082 if (!geteuid())
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002083 vps1.var_text = "PS1=# ";
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002084#endif
2085 vp = varinit;
Denis Vlasenko80b8b392007-06-25 10:55:35 +00002086 end = vp + ARRAY_SIZE(varinit);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002087 do {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002088 vpp = hashvar(vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002089 vp->next = *vpp;
2090 *vpp = vp;
2091 } while (++vp < end);
2092}
2093
2094static struct var **
2095findvar(struct var **vpp, const char *name)
2096{
2097 for (; *vpp; vpp = &(*vpp)->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002098 if (varcmp((*vpp)->var_text, name) == 0) {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002099 break;
2100 }
2101 }
2102 return vpp;
2103}
2104
2105/*
2106 * Find the value of a variable. Returns NULL if not set.
2107 */
Denys Vlasenko03dad222010-01-12 23:29:57 +01002108static const char* FAST_FUNC
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002109lookupvar(const char *name)
2110{
2111 struct var *v;
2112
2113 v = *findvar(hashvar(name), name);
2114 if (v) {
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002115#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002116 /*
2117 * Dynamic variables are implemented roughly the same way they are
2118 * in bash. Namely, they're "special" so long as they aren't unset.
2119 * As soon as they're unset, they're no longer dynamic, and dynamic
2120 * lookup will no longer happen at that point. -- PFM.
2121 */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002122 if (v->flags & VDYNAMIC)
2123 v->var_func(NULL);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002124#endif
2125 if (!(v->flags & VUNSET))
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002126 return var_end(v->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002127 }
2128 return NULL;
2129}
2130
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02002131static void reinit_unicode_for_ash(void)
2132{
2133 /* Unicode support should be activated even if LANG is set
2134 * _during_ shell execution, not only if it was set when
2135 * shell was started. Therefore, re-check LANG every time:
2136 */
2137 if (ENABLE_FEATURE_CHECK_UNICODE_IN_ENV
2138 || ENABLE_UNICODE_USING_LOCALE
2139 ) {
2140 const char *s = lookupvar("LC_ALL");
2141 if (!s) s = lookupvar("LC_CTYPE");
2142 if (!s) s = lookupvar("LANG");
2143 reinit_unicode(s);
2144 }
2145}
2146
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002147/*
2148 * Search the environment of a builtin command.
2149 */
Mike Frysinger98c52642009-04-02 10:02:37 +00002150static const char *
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002151bltinlookup(const char *name)
2152{
2153 struct strlist *sp;
2154
2155 for (sp = cmdenviron; sp; sp = sp->next) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002156 if (varcmp(sp->text, name) == 0)
2157 return var_end(sp->text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002158 }
2159 return lookupvar(name);
2160}
2161
2162/*
2163 * Same as setvar except that the variable and value are passed in
2164 * the first argument as name=value. Since the first argument will
2165 * be actually stored in the table, it should not be a string that
2166 * will go away.
2167 * Called with interrupts off.
2168 */
2169static void
2170setvareq(char *s, int flags)
2171{
2172 struct var *vp, **vpp;
2173
2174 vpp = hashvar(s);
2175 flags |= (VEXPORT & (((unsigned) (1 - aflag)) - 1));
2176 vp = *findvar(vpp, s);
2177 if (vp) {
2178 if ((vp->flags & (VREADONLY|VDYNAMIC)) == VREADONLY) {
2179 const char *n;
2180
2181 if (flags & VNOSAVE)
2182 free(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002183 n = vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002184 ash_msg_and_raise_error("%.*s: is read only", strchrnul(n, '=') - n, n);
2185 }
2186
2187 if (flags & VNOSET)
2188 return;
2189
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002190 if (vp->var_func && !(flags & VNOFUNC))
2191 vp->var_func(var_end(s));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002192
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002193 if (!(vp->flags & (VTEXTFIXED|VSTACK)))
2194 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002195
2196 flags |= vp->flags & ~(VTEXTFIXED|VSTACK|VNOSAVE|VUNSET);
2197 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002198 /* variable s is not found */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002199 if (flags & VNOSET)
2200 return;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002201 vp = ckzalloc(sizeof(*vp));
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002202 vp->next = *vpp;
Denis Vlasenko597906c2008-02-20 16:38:54 +00002203 /*vp->func = NULL; - ckzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002204 *vpp = vp;
2205 }
2206 if (!(flags & (VTEXTFIXED|VSTACK|VNOSAVE)))
2207 s = ckstrdup(s);
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002208 vp->var_text = s;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002209 vp->flags = flags;
2210}
2211
2212/*
2213 * Set the value of a variable. The flags argument is ored with the
2214 * flags of the variable. If val is NULL, the variable is unset.
2215 */
2216static void
2217setvar(const char *name, const char *val, int flags)
2218{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002219 const char *q;
2220 char *p;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002221 char *nameeq;
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002222 size_t namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002223 size_t vallen;
2224
2225 q = endofname(name);
2226 p = strchrnul(q, '=');
2227 namelen = p - name;
2228 if (!namelen || p != q)
2229 ash_msg_and_raise_error("%.*s: bad variable name", namelen, name);
2230 vallen = 0;
2231 if (val == NULL) {
2232 flags |= VUNSET;
2233 } else {
2234 vallen = strlen(val);
2235 }
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002236
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002237 INT_OFF;
2238 nameeq = ckmalloc(namelen + vallen + 2);
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002239 p = memcpy(nameeq, name, namelen) + namelen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002240 if (val) {
2241 *p++ = '=';
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02002242 p = memcpy(p, val, vallen) + vallen;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002243 }
2244 *p = '\0';
2245 setvareq(nameeq, flags | VNOSAVE);
2246 INT_ON;
2247}
2248
Denys Vlasenko03dad222010-01-12 23:29:57 +01002249static void FAST_FUNC
2250setvar2(const char *name, const char *val)
2251{
2252 setvar(name, val, 0);
2253}
2254
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002255#if ENABLE_ASH_GETOPTS
2256/*
2257 * Safe version of setvar, returns 1 on success 0 on failure.
2258 */
2259static int
2260setvarsafe(const char *name, const char *val, int flags)
2261{
2262 int err;
2263 volatile int saveint;
2264 struct jmploc *volatile savehandler = exception_handler;
2265 struct jmploc jmploc;
2266
2267 SAVE_INT(saveint);
2268 if (setjmp(jmploc.loc))
2269 err = 1;
2270 else {
2271 exception_handler = &jmploc;
2272 setvar(name, val, flags);
2273 err = 0;
2274 }
2275 exception_handler = savehandler;
2276 RESTORE_INT(saveint);
2277 return err;
2278}
2279#endif
2280
2281/*
2282 * Unset the specified variable.
2283 */
2284static int
2285unsetvar(const char *s)
2286{
2287 struct var **vpp;
2288 struct var *vp;
2289 int retval;
2290
2291 vpp = findvar(hashvar(s), s);
2292 vp = *vpp;
2293 retval = 2;
2294 if (vp) {
2295 int flags = vp->flags;
2296
2297 retval = 1;
2298 if (flags & VREADONLY)
2299 goto out;
Denis Vlasenko448d30e2008-06-27 00:24:11 +00002300#if ENABLE_ASH_RANDOM_SUPPORT
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002301 vp->flags &= ~VDYNAMIC;
2302#endif
2303 if (flags & VUNSET)
2304 goto ok;
2305 if ((flags & VSTRFIXED) == 0) {
2306 INT_OFF;
2307 if ((flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002308 free((char*)vp->var_text);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002309 *vpp = vp->next;
2310 free(vp);
2311 INT_ON;
2312 } else {
Bernhard Reutner-Fischer200c1c42013-11-08 14:12:13 +01002313 setvar2(s, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002314 vp->flags &= ~VEXPORT;
2315 }
2316 ok:
2317 retval = 0;
2318 }
2319 out:
2320 return retval;
2321}
2322
2323/*
2324 * Process a linked list of variable assignments.
2325 */
2326static void
2327listsetvar(struct strlist *list_set_var, int flags)
2328{
2329 struct strlist *lp = list_set_var;
2330
2331 if (!lp)
2332 return;
2333 INT_OFF;
2334 do {
2335 setvareq(lp->text, flags);
Denis Vlasenko9650f362007-02-23 01:04:37 +00002336 lp = lp->next;
2337 } while (lp);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002338 INT_ON;
2339}
2340
2341/*
2342 * Generate a list of variables satisfying the given conditions.
2343 */
2344static char **
2345listvars(int on, int off, char ***end)
2346{
2347 struct var **vpp;
2348 struct var *vp;
2349 char **ep;
2350 int mask;
2351
2352 STARTSTACKSTR(ep);
2353 vpp = vartab;
2354 mask = on | off;
2355 do {
2356 for (vp = *vpp; vp; vp = vp->next) {
2357 if ((vp->flags & mask) == on) {
2358 if (ep == stackstrend())
2359 ep = growstackstr();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02002360 *ep++ = (char*)vp->var_text;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002361 }
2362 }
2363 } while (++vpp < vartab + VTABSIZE);
2364 if (ep == stackstrend())
2365 ep = growstackstr();
2366 if (end)
2367 *end = ep;
2368 *ep++ = NULL;
2369 return grabstackstr(ep);
2370}
2371
2372
2373/* ============ Path search helper
2374 *
2375 * The variable path (passed by reference) should be set to the start
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002376 * of the path before the first call; path_advance will update
2377 * this value as it proceeds. Successive calls to path_advance will return
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002378 * the possible path expansions in sequence. If an option (indicated by
2379 * a percent sign) appears in the path entry then the global variable
2380 * pathopt will be set to point to it; otherwise pathopt will be set to
2381 * NULL.
2382 */
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002383static const char *pathopt; /* set by path_advance */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002384
2385static char *
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002386path_advance(const char **path, const char *name)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002387{
2388 const char *p;
2389 char *q;
2390 const char *start;
2391 size_t len;
2392
2393 if (*path == NULL)
2394 return NULL;
2395 start = *path;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002396 for (p = start; *p && *p != ':' && *p != '%'; p++)
2397 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002398 len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */
2399 while (stackblocksize() < len)
2400 growstackblock();
2401 q = stackblock();
2402 if (p != start) {
2403 memcpy(q, start, p - start);
2404 q += p - start;
2405 *q++ = '/';
2406 }
2407 strcpy(q, name);
2408 pathopt = NULL;
2409 if (*p == '%') {
2410 pathopt = ++p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +00002411 while (*p && *p != ':')
2412 p++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002413 }
2414 if (*p == ':')
2415 *path = p + 1;
2416 else
2417 *path = NULL;
2418 return stalloc(len);
2419}
2420
2421
2422/* ============ Prompt */
2423
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +00002424static smallint doprompt; /* if set, prompt the user */
2425static smallint needprompt; /* true if interactive and at start of line */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002426
2427#if ENABLE_FEATURE_EDITING
2428static line_input_t *line_input_state;
2429static const char *cmdedit_prompt;
2430static void
2431putprompt(const char *s)
2432{
2433 if (ENABLE_ASH_EXPAND_PRMT) {
2434 free((char*)cmdedit_prompt);
Denis Vlasenko4222ae42007-02-25 02:37:49 +00002435 cmdedit_prompt = ckstrdup(s);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002436 return;
2437 }
2438 cmdedit_prompt = s;
2439}
2440#else
2441static void
2442putprompt(const char *s)
2443{
2444 out2str(s);
2445}
2446#endif
2447
2448#if ENABLE_ASH_EXPAND_PRMT
2449/* expandstr() needs parsing machinery, so it is far away ahead... */
2450static const char *expandstr(const char *ps);
2451#else
2452#define expandstr(s) s
2453#endif
2454
2455static void
Denys Vlasenko958581a2010-09-12 15:04:27 +02002456setprompt_if(smallint do_set, int whichprompt)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002457{
2458 const char *prompt;
Denys Vlasenko958581a2010-09-12 15:04:27 +02002459 IF_ASH_EXPAND_PRMT(struct stackmark smark;)
2460
2461 if (!do_set)
2462 return;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002463
2464 needprompt = 0;
2465
2466 switch (whichprompt) {
2467 case 1:
2468 prompt = ps1val();
2469 break;
2470 case 2:
2471 prompt = ps2val();
2472 break;
2473 default: /* 0 */
2474 prompt = nullstr;
2475 }
2476#if ENABLE_ASH_EXPAND_PRMT
2477 setstackmark(&smark);
2478 stalloc(stackblocksize());
2479#endif
2480 putprompt(expandstr(prompt));
2481#if ENABLE_ASH_EXPAND_PRMT
2482 popstackmark(&smark);
2483#endif
2484}
2485
2486
2487/* ============ The cd and pwd commands */
2488
2489#define CD_PHYSICAL 1
2490#define CD_PRINT 2
2491
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002492static int
2493cdopt(void)
2494{
2495 int flags = 0;
2496 int i, j;
2497
2498 j = 'L';
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02002499 while ((i = nextopt("LP")) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002500 if (i != j) {
2501 flags ^= CD_PHYSICAL;
2502 j = i;
2503 }
2504 }
2505
2506 return flags;
2507}
2508
2509/*
2510 * Update curdir (the name of the current directory) in response to a
2511 * cd command.
2512 */
2513static const char *
2514updatepwd(const char *dir)
2515{
2516 char *new;
2517 char *p;
2518 char *cdcomppath;
2519 const char *lim;
2520
2521 cdcomppath = ststrdup(dir);
2522 STARTSTACKSTR(new);
2523 if (*dir != '/') {
2524 if (curdir == nullstr)
2525 return 0;
2526 new = stack_putstr(curdir, new);
2527 }
2528 new = makestrspace(strlen(dir) + 2, new);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00002529 lim = (char *)stackblock() + 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002530 if (*dir != '/') {
2531 if (new[-1] != '/')
2532 USTPUTC('/', new);
2533 if (new > lim && *lim == '/')
2534 lim++;
2535 } else {
2536 USTPUTC('/', new);
2537 cdcomppath++;
2538 if (dir[1] == '/' && dir[2] != '/') {
2539 USTPUTC('/', new);
2540 cdcomppath++;
2541 lim++;
2542 }
2543 }
2544 p = strtok(cdcomppath, "/");
2545 while (p) {
2546 switch (*p) {
2547 case '.':
2548 if (p[1] == '.' && p[2] == '\0') {
2549 while (new > lim) {
2550 STUNPUTC(new);
2551 if (new[-1] == '/')
2552 break;
2553 }
2554 break;
Denis Vlasenko16abcd92007-04-13 23:59:52 +00002555 }
2556 if (p[1] == '\0')
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002557 break;
2558 /* fall through */
2559 default:
2560 new = stack_putstr(p, new);
2561 USTPUTC('/', new);
2562 }
2563 p = strtok(0, "/");
2564 }
2565 if (new > lim)
2566 STUNPUTC(new);
2567 *new = 0;
2568 return stackblock();
2569}
2570
2571/*
2572 * Find out what the current directory is. If we already know the current
2573 * directory, this routine returns immediately.
2574 */
2575static char *
2576getpwd(void)
2577{
Denis Vlasenko01631112007-12-16 17:20:38 +00002578 char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002579 return dir ? dir : nullstr;
2580}
2581
2582static void
2583setpwd(const char *val, int setold)
2584{
2585 char *oldcur, *dir;
2586
2587 oldcur = dir = curdir;
2588
2589 if (setold) {
2590 setvar("OLDPWD", oldcur, VEXPORT);
2591 }
2592 INT_OFF;
2593 if (physdir != nullstr) {
2594 if (physdir != oldcur)
2595 free(physdir);
2596 physdir = nullstr;
2597 }
2598 if (oldcur == val || !val) {
2599 char *s = getpwd();
2600 physdir = s;
2601 if (!val)
2602 dir = s;
2603 } else
2604 dir = ckstrdup(val);
2605 if (oldcur != dir && oldcur != nullstr) {
2606 free(oldcur);
2607 }
2608 curdir = dir;
2609 INT_ON;
2610 setvar("PWD", dir, VEXPORT);
2611}
2612
2613static void hashcd(void);
2614
2615/*
2616 * Actually do the chdir. We also call hashcd to let the routines in exec.c
2617 * know that the current directory has changed.
2618 */
2619static int
2620docd(const char *dest, int flags)
2621{
Denys Vlasenko4b1100e2010-03-05 14:10:54 +01002622 const char *dir = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002623 int err;
2624
2625 TRACE(("docd(\"%s\", %d) called\n", dest, flags));
2626
2627 INT_OFF;
2628 if (!(flags & CD_PHYSICAL)) {
2629 dir = updatepwd(dest);
2630 if (dir)
2631 dest = dir;
2632 }
2633 err = chdir(dest);
2634 if (err)
2635 goto out;
2636 setpwd(dir, 1);
2637 hashcd();
2638 out:
2639 INT_ON;
2640 return err;
2641}
2642
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002643static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002644cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002645{
2646 const char *dest;
2647 const char *path;
2648 const char *p;
2649 char c;
2650 struct stat statb;
2651 int flags;
2652
2653 flags = cdopt();
2654 dest = *argptr;
2655 if (!dest)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002656 dest = bltinlookup("HOME");
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002657 else if (LONE_DASH(dest)) {
2658 dest = bltinlookup("OLDPWD");
2659 flags |= CD_PRINT;
2660 }
2661 if (!dest)
2662 dest = nullstr;
2663 if (*dest == '/')
2664 goto step7;
2665 if (*dest == '.') {
2666 c = dest[1];
2667 dotdot:
2668 switch (c) {
2669 case '\0':
2670 case '/':
2671 goto step6;
2672 case '.':
2673 c = dest[2];
2674 if (c != '.')
2675 goto dotdot;
2676 }
2677 }
2678 if (!*dest)
2679 dest = ".";
2680 path = bltinlookup("CDPATH");
2681 if (!path) {
2682 step6:
2683 step7:
2684 p = dest;
2685 goto docd;
2686 }
2687 do {
2688 c = *path;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02002689 p = path_advance(&path, dest);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002690 if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
2691 if (c && c != ':')
2692 flags |= CD_PRINT;
2693 docd:
2694 if (!docd(p, flags))
2695 goto out;
2696 break;
2697 }
2698 } while (path);
2699 ash_msg_and_raise_error("can't cd to %s", dest);
2700 /* NOTREACHED */
2701 out:
2702 if (flags & CD_PRINT)
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002703 out1fmt("%s\n", curdir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002704 return 0;
2705}
2706
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02002707static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00002708pwdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002709{
2710 int flags;
2711 const char *dir = curdir;
2712
2713 flags = cdopt();
2714 if (flags) {
2715 if (physdir == nullstr)
2716 setpwd(dir, 0);
2717 dir = physdir;
2718 }
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02002719 out1fmt("%s\n", dir);
Denis Vlasenkoaa744452007-02-23 01:04:22 +00002720 return 0;
2721}
2722
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002723
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00002724/* ============ ... */
Eric Andersenc470f442003-07-28 09:56:35 +00002725
Denis Vlasenko834dee72008-10-07 09:18:30 +00002726
Denys Vlasenko82dd14a2010-05-17 10:10:01 +02002727#define IBUFSIZ (ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 1024)
Eric Andersenc470f442003-07-28 09:56:35 +00002728
Eric Andersenc470f442003-07-28 09:56:35 +00002729/* Syntax classes */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002730#define CWORD 0 /* character is nothing special */
2731#define CNL 1 /* newline character */
2732#define CBACK 2 /* a backslash character */
2733#define CSQUOTE 3 /* single quote */
2734#define CDQUOTE 4 /* double quote */
Eric Andersenc470f442003-07-28 09:56:35 +00002735#define CENDQUOTE 5 /* a terminating quote */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002736#define CBQUOTE 6 /* backwards single quote */
2737#define CVAR 7 /* a dollar sign */
2738#define CENDVAR 8 /* a '}' character */
2739#define CLP 9 /* a left paren in arithmetic */
2740#define CRP 10 /* a right paren in arithmetic */
Eric Andersenc470f442003-07-28 09:56:35 +00002741#define CENDFILE 11 /* end of file */
Denis Vlasenko834dee72008-10-07 09:18:30 +00002742#define CCTL 12 /* like CWORD, except it must be escaped */
2743#define CSPCL 13 /* these terminate a word */
2744#define CIGN 14 /* character should be ignored */
Eric Andersenc470f442003-07-28 09:56:35 +00002745
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002746#define PEOF 256
Denis Vlasenko131ae172007-02-18 13:00:19 +00002747#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002748# define PEOA 257
Eric Andersenc470f442003-07-28 09:56:35 +00002749#endif
2750
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002751#define USE_SIT_FUNCTION ENABLE_ASH_OPTIMIZE_FOR_SIZE
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002752
Mike Frysinger98c52642009-04-02 10:02:37 +00002753#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002754# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8) | (d << 12))
Eric Andersenc470f442003-07-28 09:56:35 +00002755#else
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002756# define SIT_ITEM(a,b,c,d) (a | (b << 4) | (c << 8))
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002757#endif
Denys Vlasenko068d3862009-11-29 01:41:11 +01002758static const uint16_t S_I_T[] = {
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002759#if ENABLE_ASH_ALIAS
2760 SIT_ITEM(CSPCL , CIGN , CIGN , CIGN ), /* 0, PEOA */
2761#endif
2762 SIT_ITEM(CSPCL , CWORD , CWORD, CWORD ), /* 1, ' ' */
2763 SIT_ITEM(CNL , CNL , CNL , CNL ), /* 2, \n */
2764 SIT_ITEM(CWORD , CCTL , CCTL , CWORD ), /* 3, !*-/:=?[]~ */
2765 SIT_ITEM(CDQUOTE , CENDQUOTE, CWORD, CWORD ), /* 4, '"' */
2766 SIT_ITEM(CVAR , CVAR , CWORD, CVAR ), /* 5, $ */
2767 SIT_ITEM(CSQUOTE , CWORD , CENDQUOTE, CWORD), /* 6, "'" */
2768 SIT_ITEM(CSPCL , CWORD , CWORD, CLP ), /* 7, ( */
2769 SIT_ITEM(CSPCL , CWORD , CWORD, CRP ), /* 8, ) */
2770 SIT_ITEM(CBACK , CBACK , CCTL , CBACK ), /* 9, \ */
2771 SIT_ITEM(CBQUOTE , CBQUOTE , CWORD, CBQUOTE), /* 10, ` */
2772 SIT_ITEM(CENDVAR , CENDVAR , CWORD, CENDVAR), /* 11, } */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002773#if !USE_SIT_FUNCTION
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002774 SIT_ITEM(CENDFILE, CENDFILE , CENDFILE, CENDFILE),/* 12, PEOF */
2775 SIT_ITEM(CWORD , CWORD , CWORD, CWORD ), /* 13, 0-9A-Za-z */
2776 SIT_ITEM(CCTL , CCTL , CCTL , CCTL ) /* 14, CTLESC ... */
2777#endif
2778#undef SIT_ITEM
Eric Andersenc470f442003-07-28 09:56:35 +00002779};
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002780/* Constants below must match table above */
2781enum {
2782#if ENABLE_ASH_ALIAS
2783 CSPCL_CIGN_CIGN_CIGN , /* 0 */
2784#endif
2785 CSPCL_CWORD_CWORD_CWORD , /* 1 */
2786 CNL_CNL_CNL_CNL , /* 2 */
2787 CWORD_CCTL_CCTL_CWORD , /* 3 */
2788 CDQUOTE_CENDQUOTE_CWORD_CWORD , /* 4 */
2789 CVAR_CVAR_CWORD_CVAR , /* 5 */
2790 CSQUOTE_CWORD_CENDQUOTE_CWORD , /* 6 */
2791 CSPCL_CWORD_CWORD_CLP , /* 7 */
2792 CSPCL_CWORD_CWORD_CRP , /* 8 */
2793 CBACK_CBACK_CCTL_CBACK , /* 9 */
2794 CBQUOTE_CBQUOTE_CWORD_CBQUOTE , /* 10 */
2795 CENDVAR_CENDVAR_CWORD_CENDVAR , /* 11 */
2796 CENDFILE_CENDFILE_CENDFILE_CENDFILE, /* 12 */
2797 CWORD_CWORD_CWORD_CWORD , /* 13 */
2798 CCTL_CCTL_CCTL_CCTL , /* 14 */
2799};
Eric Andersen2870d962001-07-02 17:27:21 +00002800
Denys Vlasenkocd716832009-11-28 22:14:02 +01002801/* c in SIT(c, syntax) must be an *unsigned char* or PEOA or PEOF,
2802 * caller must ensure proper cast on it if c is *char_ptr!
2803 */
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002804/* Values for syntax param */
2805#define BASESYNTAX 0 /* not in quotes */
2806#define DQSYNTAX 1 /* in double quotes */
2807#define SQSYNTAX 2 /* in single quotes */
2808#define ARISYNTAX 3 /* in arithmetic */
2809#define PSSYNTAX 4 /* prompt. never passed to SIT() */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002810
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002811#if USE_SIT_FUNCTION
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002812
Denis Vlasenko0c032a42007-02-23 01:03:40 +00002813static int
2814SIT(int c, int syntax)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002815{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00002816 static const char spec_symbls[] ALIGN1 = "\t\n !\"$&'()*-/:;<=>?[\\]`|}~";
Denys Vlasenkocd716832009-11-28 22:14:02 +01002817# if ENABLE_ASH_ALIAS
2818 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002819 1, 2, 1, 3, 4, 5, 1, 6, /* "\t\n !\"$&'" */
2820 7, 8, 3, 3, 3, 3, 1, 1, /* "()*-/:;<" */
2821 3, 1, 3, 3, 9, 3, 10, 1, /* "=>?[\\]`|" */
2822 11, 3 /* "}~" */
2823 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002824# else
2825 static const uint8_t syntax_index_table[] ALIGN1 = {
Eric Andersenc470f442003-07-28 09:56:35 +00002826 0, 1, 0, 2, 3, 4, 0, 5, /* "\t\n !\"$&'" */
2827 6, 7, 2, 2, 2, 2, 0, 0, /* "()*-/:;<" */
2828 2, 0, 2, 2, 8, 2, 9, 0, /* "=>?[\\]`|" */
2829 10, 2 /* "}~" */
2830 };
Denys Vlasenkocd716832009-11-28 22:14:02 +01002831# endif
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002832 const char *s;
2833 int indx;
2834
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002835 if (c == PEOF)
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002836 return CENDFILE;
Denys Vlasenkocd716832009-11-28 22:14:02 +01002837# if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002838 if (c == PEOA)
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002839 indx = 0;
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002840 else
Denys Vlasenkocd716832009-11-28 22:14:02 +01002841# endif
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002842 {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002843 /* Cast is purely for paranoia here,
2844 * just in case someone passed signed char to us */
2845 if ((unsigned char)c >= CTL_FIRST
2846 && (unsigned char)c <= CTL_LAST
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002847 ) {
2848 return CCTL;
2849 }
2850 s = strchrnul(spec_symbls, c);
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01002851 if (*s == '\0')
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002852 return CWORD;
Denis Vlasenko0dfe1d22009-04-02 12:57:38 +00002853 indx = syntax_index_table[s - spec_symbls];
2854 }
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002855 return (S_I_T[indx] >> (syntax*4)) & 0xf;
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002856}
2857
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00002858#else /* !USE_SIT_FUNCTION */
Manuel Novoa III 16815d42001-08-10 19:36:07 +00002859
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01002860static const uint8_t syntax_index_table[] = {
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00002861 /* BASESYNTAX_DQSYNTAX_SQSYNTAX_ARISYNTAX */
Denys Vlasenkocd716832009-11-28 22:14:02 +01002862 /* 0 */ CWORD_CWORD_CWORD_CWORD,
2863 /* 1 */ CWORD_CWORD_CWORD_CWORD,
2864 /* 2 */ CWORD_CWORD_CWORD_CWORD,
2865 /* 3 */ CWORD_CWORD_CWORD_CWORD,
2866 /* 4 */ CWORD_CWORD_CWORD_CWORD,
2867 /* 5 */ CWORD_CWORD_CWORD_CWORD,
2868 /* 6 */ CWORD_CWORD_CWORD_CWORD,
2869 /* 7 */ CWORD_CWORD_CWORD_CWORD,
2870 /* 8 */ CWORD_CWORD_CWORD_CWORD,
2871 /* 9 "\t" */ CSPCL_CWORD_CWORD_CWORD,
2872 /* 10 "\n" */ CNL_CNL_CNL_CNL,
2873 /* 11 */ CWORD_CWORD_CWORD_CWORD,
2874 /* 12 */ CWORD_CWORD_CWORD_CWORD,
2875 /* 13 */ CWORD_CWORD_CWORD_CWORD,
2876 /* 14 */ CWORD_CWORD_CWORD_CWORD,
2877 /* 15 */ CWORD_CWORD_CWORD_CWORD,
2878 /* 16 */ CWORD_CWORD_CWORD_CWORD,
2879 /* 17 */ CWORD_CWORD_CWORD_CWORD,
2880 /* 18 */ CWORD_CWORD_CWORD_CWORD,
2881 /* 19 */ CWORD_CWORD_CWORD_CWORD,
2882 /* 20 */ CWORD_CWORD_CWORD_CWORD,
2883 /* 21 */ CWORD_CWORD_CWORD_CWORD,
2884 /* 22 */ CWORD_CWORD_CWORD_CWORD,
2885 /* 23 */ CWORD_CWORD_CWORD_CWORD,
2886 /* 24 */ CWORD_CWORD_CWORD_CWORD,
2887 /* 25 */ CWORD_CWORD_CWORD_CWORD,
2888 /* 26 */ CWORD_CWORD_CWORD_CWORD,
2889 /* 27 */ CWORD_CWORD_CWORD_CWORD,
2890 /* 28 */ CWORD_CWORD_CWORD_CWORD,
2891 /* 29 */ CWORD_CWORD_CWORD_CWORD,
2892 /* 30 */ CWORD_CWORD_CWORD_CWORD,
2893 /* 31 */ CWORD_CWORD_CWORD_CWORD,
2894 /* 32 " " */ CSPCL_CWORD_CWORD_CWORD,
2895 /* 33 "!" */ CWORD_CCTL_CCTL_CWORD,
2896 /* 34 """ */ CDQUOTE_CENDQUOTE_CWORD_CWORD,
2897 /* 35 "#" */ CWORD_CWORD_CWORD_CWORD,
2898 /* 36 "$" */ CVAR_CVAR_CWORD_CVAR,
2899 /* 37 "%" */ CWORD_CWORD_CWORD_CWORD,
2900 /* 38 "&" */ CSPCL_CWORD_CWORD_CWORD,
2901 /* 39 "'" */ CSQUOTE_CWORD_CENDQUOTE_CWORD,
2902 /* 40 "(" */ CSPCL_CWORD_CWORD_CLP,
2903 /* 41 ")" */ CSPCL_CWORD_CWORD_CRP,
2904 /* 42 "*" */ CWORD_CCTL_CCTL_CWORD,
2905 /* 43 "+" */ CWORD_CWORD_CWORD_CWORD,
2906 /* 44 "," */ CWORD_CWORD_CWORD_CWORD,
2907 /* 45 "-" */ CWORD_CCTL_CCTL_CWORD,
2908 /* 46 "." */ CWORD_CWORD_CWORD_CWORD,
2909 /* 47 "/" */ CWORD_CCTL_CCTL_CWORD,
2910 /* 48 "0" */ CWORD_CWORD_CWORD_CWORD,
2911 /* 49 "1" */ CWORD_CWORD_CWORD_CWORD,
2912 /* 50 "2" */ CWORD_CWORD_CWORD_CWORD,
2913 /* 51 "3" */ CWORD_CWORD_CWORD_CWORD,
2914 /* 52 "4" */ CWORD_CWORD_CWORD_CWORD,
2915 /* 53 "5" */ CWORD_CWORD_CWORD_CWORD,
2916 /* 54 "6" */ CWORD_CWORD_CWORD_CWORD,
2917 /* 55 "7" */ CWORD_CWORD_CWORD_CWORD,
2918 /* 56 "8" */ CWORD_CWORD_CWORD_CWORD,
2919 /* 57 "9" */ CWORD_CWORD_CWORD_CWORD,
2920 /* 58 ":" */ CWORD_CCTL_CCTL_CWORD,
2921 /* 59 ";" */ CSPCL_CWORD_CWORD_CWORD,
2922 /* 60 "<" */ CSPCL_CWORD_CWORD_CWORD,
2923 /* 61 "=" */ CWORD_CCTL_CCTL_CWORD,
2924 /* 62 ">" */ CSPCL_CWORD_CWORD_CWORD,
2925 /* 63 "?" */ CWORD_CCTL_CCTL_CWORD,
2926 /* 64 "@" */ CWORD_CWORD_CWORD_CWORD,
2927 /* 65 "A" */ CWORD_CWORD_CWORD_CWORD,
2928 /* 66 "B" */ CWORD_CWORD_CWORD_CWORD,
2929 /* 67 "C" */ CWORD_CWORD_CWORD_CWORD,
2930 /* 68 "D" */ CWORD_CWORD_CWORD_CWORD,
2931 /* 69 "E" */ CWORD_CWORD_CWORD_CWORD,
2932 /* 70 "F" */ CWORD_CWORD_CWORD_CWORD,
2933 /* 71 "G" */ CWORD_CWORD_CWORD_CWORD,
2934 /* 72 "H" */ CWORD_CWORD_CWORD_CWORD,
2935 /* 73 "I" */ CWORD_CWORD_CWORD_CWORD,
2936 /* 74 "J" */ CWORD_CWORD_CWORD_CWORD,
2937 /* 75 "K" */ CWORD_CWORD_CWORD_CWORD,
2938 /* 76 "L" */ CWORD_CWORD_CWORD_CWORD,
2939 /* 77 "M" */ CWORD_CWORD_CWORD_CWORD,
2940 /* 78 "N" */ CWORD_CWORD_CWORD_CWORD,
2941 /* 79 "O" */ CWORD_CWORD_CWORD_CWORD,
2942 /* 80 "P" */ CWORD_CWORD_CWORD_CWORD,
2943 /* 81 "Q" */ CWORD_CWORD_CWORD_CWORD,
2944 /* 82 "R" */ CWORD_CWORD_CWORD_CWORD,
2945 /* 83 "S" */ CWORD_CWORD_CWORD_CWORD,
2946 /* 84 "T" */ CWORD_CWORD_CWORD_CWORD,
2947 /* 85 "U" */ CWORD_CWORD_CWORD_CWORD,
2948 /* 86 "V" */ CWORD_CWORD_CWORD_CWORD,
2949 /* 87 "W" */ CWORD_CWORD_CWORD_CWORD,
2950 /* 88 "X" */ CWORD_CWORD_CWORD_CWORD,
2951 /* 89 "Y" */ CWORD_CWORD_CWORD_CWORD,
2952 /* 90 "Z" */ CWORD_CWORD_CWORD_CWORD,
2953 /* 91 "[" */ CWORD_CCTL_CCTL_CWORD,
2954 /* 92 "\" */ CBACK_CBACK_CCTL_CBACK,
2955 /* 93 "]" */ CWORD_CCTL_CCTL_CWORD,
2956 /* 94 "^" */ CWORD_CWORD_CWORD_CWORD,
2957 /* 95 "_" */ CWORD_CWORD_CWORD_CWORD,
2958 /* 96 "`" */ CBQUOTE_CBQUOTE_CWORD_CBQUOTE,
2959 /* 97 "a" */ CWORD_CWORD_CWORD_CWORD,
2960 /* 98 "b" */ CWORD_CWORD_CWORD_CWORD,
2961 /* 99 "c" */ CWORD_CWORD_CWORD_CWORD,
2962 /* 100 "d" */ CWORD_CWORD_CWORD_CWORD,
2963 /* 101 "e" */ CWORD_CWORD_CWORD_CWORD,
2964 /* 102 "f" */ CWORD_CWORD_CWORD_CWORD,
2965 /* 103 "g" */ CWORD_CWORD_CWORD_CWORD,
2966 /* 104 "h" */ CWORD_CWORD_CWORD_CWORD,
2967 /* 105 "i" */ CWORD_CWORD_CWORD_CWORD,
2968 /* 106 "j" */ CWORD_CWORD_CWORD_CWORD,
2969 /* 107 "k" */ CWORD_CWORD_CWORD_CWORD,
2970 /* 108 "l" */ CWORD_CWORD_CWORD_CWORD,
2971 /* 109 "m" */ CWORD_CWORD_CWORD_CWORD,
2972 /* 110 "n" */ CWORD_CWORD_CWORD_CWORD,
2973 /* 111 "o" */ CWORD_CWORD_CWORD_CWORD,
2974 /* 112 "p" */ CWORD_CWORD_CWORD_CWORD,
2975 /* 113 "q" */ CWORD_CWORD_CWORD_CWORD,
2976 /* 114 "r" */ CWORD_CWORD_CWORD_CWORD,
2977 /* 115 "s" */ CWORD_CWORD_CWORD_CWORD,
2978 /* 116 "t" */ CWORD_CWORD_CWORD_CWORD,
2979 /* 117 "u" */ CWORD_CWORD_CWORD_CWORD,
2980 /* 118 "v" */ CWORD_CWORD_CWORD_CWORD,
2981 /* 119 "w" */ CWORD_CWORD_CWORD_CWORD,
2982 /* 120 "x" */ CWORD_CWORD_CWORD_CWORD,
2983 /* 121 "y" */ CWORD_CWORD_CWORD_CWORD,
2984 /* 122 "z" */ CWORD_CWORD_CWORD_CWORD,
2985 /* 123 "{" */ CWORD_CWORD_CWORD_CWORD,
2986 /* 124 "|" */ CSPCL_CWORD_CWORD_CWORD,
2987 /* 125 "}" */ CENDVAR_CENDVAR_CWORD_CENDVAR,
2988 /* 126 "~" */ CWORD_CCTL_CCTL_CWORD,
2989 /* 127 del */ CWORD_CWORD_CWORD_CWORD,
2990 /* 128 0x80 */ CWORD_CWORD_CWORD_CWORD,
2991 /* 129 CTLESC */ CCTL_CCTL_CCTL_CCTL,
2992 /* 130 CTLVAR */ CCTL_CCTL_CCTL_CCTL,
2993 /* 131 CTLENDVAR */ CCTL_CCTL_CCTL_CCTL,
2994 /* 132 CTLBACKQ */ CCTL_CCTL_CCTL_CCTL,
2995 /* 133 CTLQUOTE */ CCTL_CCTL_CCTL_CCTL,
2996 /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL,
2997 /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL,
2998 /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL,
2999 /* 137 */ CWORD_CWORD_CWORD_CWORD,
3000 /* 138 */ CWORD_CWORD_CWORD_CWORD,
3001 /* 139 */ CWORD_CWORD_CWORD_CWORD,
3002 /* 140 */ CWORD_CWORD_CWORD_CWORD,
3003 /* 141 */ CWORD_CWORD_CWORD_CWORD,
3004 /* 142 */ CWORD_CWORD_CWORD_CWORD,
3005 /* 143 */ CWORD_CWORD_CWORD_CWORD,
3006 /* 144 */ CWORD_CWORD_CWORD_CWORD,
3007 /* 145 */ CWORD_CWORD_CWORD_CWORD,
3008 /* 146 */ CWORD_CWORD_CWORD_CWORD,
3009 /* 147 */ CWORD_CWORD_CWORD_CWORD,
3010 /* 148 */ CWORD_CWORD_CWORD_CWORD,
3011 /* 149 */ CWORD_CWORD_CWORD_CWORD,
3012 /* 150 */ CWORD_CWORD_CWORD_CWORD,
3013 /* 151 */ CWORD_CWORD_CWORD_CWORD,
3014 /* 152 */ CWORD_CWORD_CWORD_CWORD,
3015 /* 153 */ CWORD_CWORD_CWORD_CWORD,
3016 /* 154 */ CWORD_CWORD_CWORD_CWORD,
3017 /* 155 */ CWORD_CWORD_CWORD_CWORD,
3018 /* 156 */ CWORD_CWORD_CWORD_CWORD,
3019 /* 157 */ CWORD_CWORD_CWORD_CWORD,
3020 /* 158 */ CWORD_CWORD_CWORD_CWORD,
3021 /* 159 */ CWORD_CWORD_CWORD_CWORD,
3022 /* 160 */ CWORD_CWORD_CWORD_CWORD,
3023 /* 161 */ CWORD_CWORD_CWORD_CWORD,
3024 /* 162 */ CWORD_CWORD_CWORD_CWORD,
3025 /* 163 */ CWORD_CWORD_CWORD_CWORD,
3026 /* 164 */ CWORD_CWORD_CWORD_CWORD,
3027 /* 165 */ CWORD_CWORD_CWORD_CWORD,
3028 /* 166 */ CWORD_CWORD_CWORD_CWORD,
3029 /* 167 */ CWORD_CWORD_CWORD_CWORD,
3030 /* 168 */ CWORD_CWORD_CWORD_CWORD,
3031 /* 169 */ CWORD_CWORD_CWORD_CWORD,
3032 /* 170 */ CWORD_CWORD_CWORD_CWORD,
3033 /* 171 */ CWORD_CWORD_CWORD_CWORD,
3034 /* 172 */ CWORD_CWORD_CWORD_CWORD,
3035 /* 173 */ CWORD_CWORD_CWORD_CWORD,
3036 /* 174 */ CWORD_CWORD_CWORD_CWORD,
3037 /* 175 */ CWORD_CWORD_CWORD_CWORD,
3038 /* 176 */ CWORD_CWORD_CWORD_CWORD,
3039 /* 177 */ CWORD_CWORD_CWORD_CWORD,
3040 /* 178 */ CWORD_CWORD_CWORD_CWORD,
3041 /* 179 */ CWORD_CWORD_CWORD_CWORD,
3042 /* 180 */ CWORD_CWORD_CWORD_CWORD,
3043 /* 181 */ CWORD_CWORD_CWORD_CWORD,
3044 /* 182 */ CWORD_CWORD_CWORD_CWORD,
3045 /* 183 */ CWORD_CWORD_CWORD_CWORD,
3046 /* 184 */ CWORD_CWORD_CWORD_CWORD,
3047 /* 185 */ CWORD_CWORD_CWORD_CWORD,
3048 /* 186 */ CWORD_CWORD_CWORD_CWORD,
3049 /* 187 */ CWORD_CWORD_CWORD_CWORD,
3050 /* 188 */ CWORD_CWORD_CWORD_CWORD,
3051 /* 189 */ CWORD_CWORD_CWORD_CWORD,
3052 /* 190 */ CWORD_CWORD_CWORD_CWORD,
3053 /* 191 */ CWORD_CWORD_CWORD_CWORD,
3054 /* 192 */ CWORD_CWORD_CWORD_CWORD,
3055 /* 193 */ CWORD_CWORD_CWORD_CWORD,
3056 /* 194 */ CWORD_CWORD_CWORD_CWORD,
3057 /* 195 */ CWORD_CWORD_CWORD_CWORD,
3058 /* 196 */ CWORD_CWORD_CWORD_CWORD,
3059 /* 197 */ CWORD_CWORD_CWORD_CWORD,
3060 /* 198 */ CWORD_CWORD_CWORD_CWORD,
3061 /* 199 */ CWORD_CWORD_CWORD_CWORD,
3062 /* 200 */ CWORD_CWORD_CWORD_CWORD,
3063 /* 201 */ CWORD_CWORD_CWORD_CWORD,
3064 /* 202 */ CWORD_CWORD_CWORD_CWORD,
3065 /* 203 */ CWORD_CWORD_CWORD_CWORD,
3066 /* 204 */ CWORD_CWORD_CWORD_CWORD,
3067 /* 205 */ CWORD_CWORD_CWORD_CWORD,
3068 /* 206 */ CWORD_CWORD_CWORD_CWORD,
3069 /* 207 */ CWORD_CWORD_CWORD_CWORD,
3070 /* 208 */ CWORD_CWORD_CWORD_CWORD,
3071 /* 209 */ CWORD_CWORD_CWORD_CWORD,
3072 /* 210 */ CWORD_CWORD_CWORD_CWORD,
3073 /* 211 */ CWORD_CWORD_CWORD_CWORD,
3074 /* 212 */ CWORD_CWORD_CWORD_CWORD,
3075 /* 213 */ CWORD_CWORD_CWORD_CWORD,
3076 /* 214 */ CWORD_CWORD_CWORD_CWORD,
3077 /* 215 */ CWORD_CWORD_CWORD_CWORD,
3078 /* 216 */ CWORD_CWORD_CWORD_CWORD,
3079 /* 217 */ CWORD_CWORD_CWORD_CWORD,
3080 /* 218 */ CWORD_CWORD_CWORD_CWORD,
3081 /* 219 */ CWORD_CWORD_CWORD_CWORD,
3082 /* 220 */ CWORD_CWORD_CWORD_CWORD,
3083 /* 221 */ CWORD_CWORD_CWORD_CWORD,
3084 /* 222 */ CWORD_CWORD_CWORD_CWORD,
3085 /* 223 */ CWORD_CWORD_CWORD_CWORD,
3086 /* 224 */ CWORD_CWORD_CWORD_CWORD,
3087 /* 225 */ CWORD_CWORD_CWORD_CWORD,
3088 /* 226 */ CWORD_CWORD_CWORD_CWORD,
3089 /* 227 */ CWORD_CWORD_CWORD_CWORD,
3090 /* 228 */ CWORD_CWORD_CWORD_CWORD,
3091 /* 229 */ CWORD_CWORD_CWORD_CWORD,
3092 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3093 /* 231 */ CWORD_CWORD_CWORD_CWORD,
3094 /* 232 */ CWORD_CWORD_CWORD_CWORD,
3095 /* 233 */ CWORD_CWORD_CWORD_CWORD,
3096 /* 234 */ CWORD_CWORD_CWORD_CWORD,
3097 /* 235 */ CWORD_CWORD_CWORD_CWORD,
3098 /* 236 */ CWORD_CWORD_CWORD_CWORD,
3099 /* 237 */ CWORD_CWORD_CWORD_CWORD,
3100 /* 238 */ CWORD_CWORD_CWORD_CWORD,
3101 /* 239 */ CWORD_CWORD_CWORD_CWORD,
3102 /* 230 */ CWORD_CWORD_CWORD_CWORD,
3103 /* 241 */ CWORD_CWORD_CWORD_CWORD,
3104 /* 242 */ CWORD_CWORD_CWORD_CWORD,
3105 /* 243 */ CWORD_CWORD_CWORD_CWORD,
3106 /* 244 */ CWORD_CWORD_CWORD_CWORD,
3107 /* 245 */ CWORD_CWORD_CWORD_CWORD,
3108 /* 246 */ CWORD_CWORD_CWORD_CWORD,
3109 /* 247 */ CWORD_CWORD_CWORD_CWORD,
3110 /* 248 */ CWORD_CWORD_CWORD_CWORD,
3111 /* 249 */ CWORD_CWORD_CWORD_CWORD,
3112 /* 250 */ CWORD_CWORD_CWORD_CWORD,
3113 /* 251 */ CWORD_CWORD_CWORD_CWORD,
3114 /* 252 */ CWORD_CWORD_CWORD_CWORD,
3115 /* 253 */ CWORD_CWORD_CWORD_CWORD,
3116 /* 254 */ CWORD_CWORD_CWORD_CWORD,
3117 /* 255 */ CWORD_CWORD_CWORD_CWORD,
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003118 /* PEOF */ CENDFILE_CENDFILE_CENDFILE_CENDFILE,
Denys Vlasenkocd716832009-11-28 22:14:02 +01003119# if ENABLE_ASH_ALIAS
3120 /* PEOA */ CSPCL_CIGN_CIGN_CIGN,
3121# endif
Eric Andersen2870d962001-07-02 17:27:21 +00003122};
3123
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01003124# define SIT(c, syntax) ((S_I_T[syntax_index_table[c]] >> ((syntax)*4)) & 0xf)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00003125
Denys Vlasenko76bc2d62009-11-29 01:37:46 +01003126#endif /* !USE_SIT_FUNCTION */
Eric Andersenc470f442003-07-28 09:56:35 +00003127
Eric Andersen2870d962001-07-02 17:27:21 +00003128
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003129/* ============ Alias handling */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003130
Denis Vlasenko131ae172007-02-18 13:00:19 +00003131#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003132
3133#define ALIASINUSE 1
3134#define ALIASDEAD 2
3135
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003136struct alias {
3137 struct alias *next;
3138 char *name;
3139 char *val;
3140 int flag;
3141};
3142
Denis Vlasenko01631112007-12-16 17:20:38 +00003143
3144static struct alias **atab; // [ATABSIZE];
3145#define INIT_G_alias() do { \
3146 atab = xzalloc(ATABSIZE * sizeof(atab[0])); \
3147} while (0)
3148
Eric Andersen2870d962001-07-02 17:27:21 +00003149
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00003150static struct alias **
3151__lookupalias(const char *name) {
3152 unsigned int hashval;
3153 struct alias **app;
3154 const char *p;
3155 unsigned int ch;
3156
3157 p = name;
3158
3159 ch = (unsigned char)*p;
3160 hashval = ch << 4;
3161 while (ch) {
3162 hashval += ch;
3163 ch = (unsigned char)*++p;
3164 }
3165 app = &atab[hashval % ATABSIZE];
3166
3167 for (; *app; app = &(*app)->next) {
3168 if (strcmp(name, (*app)->name) == 0) {
3169 break;
3170 }
3171 }
3172
3173 return app;
3174}
3175
3176static struct alias *
3177lookupalias(const char *name, int check)
3178{
3179 struct alias *ap = *__lookupalias(name);
3180
3181 if (check && ap && (ap->flag & ALIASINUSE))
3182 return NULL;
3183 return ap;
3184}
3185
3186static struct alias *
3187freealias(struct alias *ap)
3188{
3189 struct alias *next;
3190
3191 if (ap->flag & ALIASINUSE) {
3192 ap->flag |= ALIASDEAD;
3193 return ap;
3194 }
3195
3196 next = ap->next;
3197 free(ap->name);
3198 free(ap->val);
3199 free(ap);
3200 return next;
3201}
Eric Andersencb57d552001-06-28 07:25:16 +00003202
Eric Andersenc470f442003-07-28 09:56:35 +00003203static void
3204setalias(const char *name, const char *val)
Eric Andersencb57d552001-06-28 07:25:16 +00003205{
3206 struct alias *ap, **app;
3207
3208 app = __lookupalias(name);
3209 ap = *app;
Denis Vlasenkob012b102007-02-19 22:43:01 +00003210 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003211 if (ap) {
3212 if (!(ap->flag & ALIASINUSE)) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003213 free(ap->val);
Eric Andersencb57d552001-06-28 07:25:16 +00003214 }
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003215 ap->val = ckstrdup(val);
Eric Andersencb57d552001-06-28 07:25:16 +00003216 ap->flag &= ~ALIASDEAD;
3217 } else {
3218 /* not found */
Denis Vlasenko597906c2008-02-20 16:38:54 +00003219 ap = ckzalloc(sizeof(struct alias));
Denis Vlasenko0c032a42007-02-23 01:03:40 +00003220 ap->name = ckstrdup(name);
3221 ap->val = ckstrdup(val);
Denis Vlasenko597906c2008-02-20 16:38:54 +00003222 /*ap->flag = 0; - ckzalloc did it */
3223 /*ap->next = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +00003224 *app = ap;
3225 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003226 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003227}
3228
Eric Andersenc470f442003-07-28 09:56:35 +00003229static int
3230unalias(const char *name)
Eric Andersen2870d962001-07-02 17:27:21 +00003231{
Eric Andersencb57d552001-06-28 07:25:16 +00003232 struct alias **app;
3233
3234 app = __lookupalias(name);
3235
3236 if (*app) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00003237 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003238 *app = freealias(*app);
Denis Vlasenkob012b102007-02-19 22:43:01 +00003239 INT_ON;
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003240 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003241 }
3242
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003243 return 1;
Eric Andersencb57d552001-06-28 07:25:16 +00003244}
3245
Eric Andersenc470f442003-07-28 09:56:35 +00003246static void
3247rmaliases(void)
Eric Andersen2870d962001-07-02 17:27:21 +00003248{
Eric Andersencb57d552001-06-28 07:25:16 +00003249 struct alias *ap, **app;
3250 int i;
3251
Denis Vlasenkob012b102007-02-19 22:43:01 +00003252 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +00003253 for (i = 0; i < ATABSIZE; i++) {
3254 app = &atab[i];
3255 for (ap = *app; ap; ap = *app) {
3256 *app = freealias(*app);
3257 if (ap == *app) {
3258 app = &ap->next;
3259 }
3260 }
3261 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00003262 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00003263}
3264
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00003265static void
3266printalias(const struct alias *ap)
3267{
3268 out1fmt("%s=%s\n", ap->name, single_quote(ap->val));
3269}
3270
Eric Andersencb57d552001-06-28 07:25:16 +00003271/*
3272 * TODO - sort output
3273 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003274static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003275aliascmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00003276{
3277 char *n, *v;
3278 int ret = 0;
3279 struct alias *ap;
3280
Denis Vlasenko68404f12008-03-17 09:00:54 +00003281 if (!argv[1]) {
Eric Andersencb57d552001-06-28 07:25:16 +00003282 int i;
3283
Denis Vlasenko68404f12008-03-17 09:00:54 +00003284 for (i = 0; i < ATABSIZE; i++) {
Eric Andersencb57d552001-06-28 07:25:16 +00003285 for (ap = atab[i]; ap; ap = ap->next) {
3286 printalias(ap);
3287 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00003288 }
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003289 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003290 }
3291 while ((n = *++argv) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00003292 v = strchr(n+1, '=');
3293 if (v == NULL) { /* n+1: funny ksh stuff */
3294 ap = *__lookupalias(n);
3295 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +00003296 fprintf(stderr, "%s: %s not found\n", "alias", n);
Eric Andersencb57d552001-06-28 07:25:16 +00003297 ret = 1;
3298 } else
3299 printalias(ap);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00003300 } else {
Eric Andersencb57d552001-06-28 07:25:16 +00003301 *v++ = '\0';
3302 setalias(n, v);
3303 }
3304 }
3305
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003306 return ret;
Eric Andersencb57d552001-06-28 07:25:16 +00003307}
3308
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003309static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003310unaliascmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +00003311{
3312 int i;
3313
3314 while ((i = nextopt("a")) != '\0') {
3315 if (i == 'a') {
3316 rmaliases();
Denis Vlasenko079f8af2006-11-27 16:49:31 +00003317 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +00003318 }
3319 }
3320 for (i = 0; *argptr; argptr++) {
3321 if (unalias(*argptr)) {
Eric Andersenc470f442003-07-28 09:56:35 +00003322 fprintf(stderr, "%s: %s not found\n", "unalias", *argptr);
Eric Andersencb57d552001-06-28 07:25:16 +00003323 i = 1;
3324 }
3325 }
3326
Denis Vlasenkod9e15f22006-11-27 16:49:55 +00003327 return i;
Eric Andersencb57d552001-06-28 07:25:16 +00003328}
Denis Vlasenkofc06f292007-02-23 21:09:35 +00003329
Denis Vlasenko131ae172007-02-18 13:00:19 +00003330#endif /* ASH_ALIAS */
Eric Andersencb57d552001-06-28 07:25:16 +00003331
Eric Andersenc470f442003-07-28 09:56:35 +00003332
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003333/* ============ jobs.c */
3334
3335/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003336#define FORK_FG 0
3337#define FORK_BG 1
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003338#define FORK_NOJOB 2
3339
3340/* mode flags for showjob(s) */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02003341#define SHOW_ONLY_PGID 0x01 /* show only pgid (jobs -p) */
3342#define SHOW_PIDS 0x02 /* show individual pids, not just one line per job */
3343#define SHOW_CHANGED 0x04 /* only jobs whose state has changed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003344
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003345/*
3346 * A job structure contains information about a job. A job is either a
3347 * single process or a set of processes contained in a pipeline. In the
3348 * latter case, pidlist will be non-NULL, and will point to a -1 terminated
3349 * array of pids.
3350 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003351struct procstat {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003352 pid_t ps_pid; /* process id */
3353 int ps_status; /* last process status from wait() */
3354 char *ps_cmd; /* text of command being run */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003355};
3356
3357struct job {
3358 struct procstat ps0; /* status of process */
3359 struct procstat *ps; /* status or processes when more than one */
3360#if JOBS
3361 int stopstatus; /* status of a stopped job */
3362#endif
3363 uint32_t
3364 nprocs: 16, /* number of processes */
3365 state: 8,
3366#define JOBRUNNING 0 /* at least one proc running */
3367#define JOBSTOPPED 1 /* all procs are stopped */
3368#define JOBDONE 2 /* all procs are completed */
3369#if JOBS
3370 sigint: 1, /* job was killed by SIGINT */
3371 jobctl: 1, /* job running under job control */
3372#endif
3373 waited: 1, /* true if this entry has been waited for */
3374 used: 1, /* true if this entry is in used */
3375 changed: 1; /* true if status has changed */
3376 struct job *prev_job; /* previous job */
3377};
3378
Denis Vlasenko68404f12008-03-17 09:00:54 +00003379static struct job *makejob(/*union node *,*/ int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003380static int forkshell(struct job *, union node *, int);
3381static int waitforjob(struct job *);
3382
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003383#if !JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003384enum { doing_jobctl = 0 };
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00003385#define setjobctl(on) do {} while (0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003386#else
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003387static smallint doing_jobctl; //references:8
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003388static void setjobctl(int);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003389#endif
3390
3391/*
Denis Vlasenko4b875702009-03-19 13:30:04 +00003392 * Ignore a signal.
3393 */
3394static void
3395ignoresig(int signo)
3396{
3397 /* Avoid unnecessary system calls. Is it already SIG_IGNed? */
3398 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
3399 /* No, need to do it */
3400 signal(signo, SIG_IGN);
3401 }
3402 sigmode[signo - 1] = S_HARD_IGN;
3403}
3404
3405/*
Denys Vlasenko238bf182010-05-18 15:49:07 +02003406 * Only one usage site - in setsignal()
Denis Vlasenko4b875702009-03-19 13:30:04 +00003407 */
3408static void
Denys Vlasenko238bf182010-05-18 15:49:07 +02003409signal_handler(int signo)
Denis Vlasenko4b875702009-03-19 13:30:04 +00003410{
3411 gotsig[signo - 1] = 1;
3412
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003413 if (signo == SIGINT && !trap[SIGINT]) {
3414 if (!suppress_int) {
3415 pending_sig = 0;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003416 raise_interrupt(); /* does not return */
3417 }
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003418 pending_int = 1;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003419 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02003420 pending_sig = signo;
Denis Vlasenko4b875702009-03-19 13:30:04 +00003421 }
3422}
3423
3424/*
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003425 * Set the signal handler for the specified signal. The routine figures
3426 * out what it should be set to.
3427 */
3428static void
3429setsignal(int signo)
3430{
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003431 char *t;
3432 char cur_act, new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003433 struct sigaction act;
3434
3435 t = trap[signo];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003436 new_act = S_DFL;
3437 if (t != NULL) { /* trap for this sig is set */
3438 new_act = S_CATCH;
3439 if (t[0] == '\0') /* trap is "": ignore this sig */
3440 new_act = S_IGN;
3441 }
3442
3443 if (rootshell && new_act == S_DFL) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003444 switch (signo) {
3445 case SIGINT:
3446 if (iflag || minusc || sflag == 0)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003447 new_act = S_CATCH;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003448 break;
3449 case SIGQUIT:
3450#if DEBUG
3451 if (debug)
3452 break;
3453#endif
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003454 /* man bash:
3455 * "In all cases, bash ignores SIGQUIT. Non-builtin
3456 * commands run by bash have signal handlers
3457 * set to the values inherited by the shell
3458 * from its parent". */
3459 new_act = S_IGN;
3460 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003461 case SIGTERM:
3462 if (iflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003463 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003464 break;
3465#if JOBS
3466 case SIGTSTP:
3467 case SIGTTOU:
3468 if (mflag)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003469 new_act = S_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003470 break;
3471#endif
3472 }
3473 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003474//TODO: if !rootshell, we reset SIGQUIT to DFL,
3475//whereas we have to restore it to what shell got on entry
3476//from the parent. See comment above
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003477
3478 t = &sigmode[signo - 1];
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003479 cur_act = *t;
3480 if (cur_act == 0) {
3481 /* current setting is not yet known */
3482 if (sigaction(signo, NULL, &act)) {
3483 /* pretend it worked; maybe we should give a warning,
3484 * but other shells don't. We don't alter sigmode,
3485 * so we retry every time.
3486 * btw, in Linux it never fails. --vda */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003487 return;
3488 }
3489 if (act.sa_handler == SIG_IGN) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003490 cur_act = S_HARD_IGN;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003491 if (mflag
3492 && (signo == SIGTSTP || signo == SIGTTIN || signo == SIGTTOU)
3493 ) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003494 cur_act = S_IGN; /* don't hard ignore these */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003495 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003496 }
3497 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003498 if (cur_act == S_HARD_IGN || cur_act == new_act)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003499 return;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003500
Denis Vlasenko991a1da2008-02-10 19:02:53 +00003501 act.sa_handler = SIG_DFL;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003502 switch (new_act) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003503 case S_CATCH:
Denys Vlasenko238bf182010-05-18 15:49:07 +02003504 act.sa_handler = signal_handler;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003505 break;
3506 case S_IGN:
3507 act.sa_handler = SIG_IGN;
3508 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003509 }
Ian Wienand89b3cba2011-04-16 20:05:14 +02003510
3511 /* flags and mask matter only if !DFL and !IGN, but we do it
3512 * for all cases for more deterministic behavior:
3513 */
3514 act.sa_flags = 0;
3515 sigfillset(&act.sa_mask);
3516
Denis Vlasenko8e2cfec2008-03-12 23:19:35 +00003517 sigaction_set(signo, &act);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003518
3519 *t = new_act;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003520}
3521
3522/* mode flags for set_curjob */
3523#define CUR_DELETE 2
3524#define CUR_RUNNING 1
3525#define CUR_STOPPED 0
3526
3527/* mode flags for dowait */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003528#define DOWAIT_NONBLOCK WNOHANG
3529#define DOWAIT_BLOCK 0
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003530
3531#if JOBS
3532/* pgrp of shell on invocation */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003533static int initialpgrp; //references:2
3534static int ttyfd = -1; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003535#endif
3536/* array of jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003537static struct job *jobtab; //5
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003538/* size of array */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003539static unsigned njobs; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003540/* current job */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003541static struct job *curjob; //lots
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003542/* number of presumed living untracked jobs */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00003543static int jobless; //4
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003544
3545static void
3546set_curjob(struct job *jp, unsigned mode)
3547{
3548 struct job *jp1;
3549 struct job **jpp, **curp;
3550
3551 /* first remove from list */
3552 jpp = curp = &curjob;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003553 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003554 jp1 = *jpp;
3555 if (jp1 == jp)
3556 break;
3557 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003558 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003559 *jpp = jp1->prev_job;
3560
3561 /* Then re-insert in correct position */
3562 jpp = curp;
3563 switch (mode) {
3564 default:
3565#if DEBUG
3566 abort();
3567#endif
3568 case CUR_DELETE:
3569 /* job being deleted */
3570 break;
3571 case CUR_RUNNING:
3572 /* newly created job or backgrounded job,
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01003573 * put after all stopped jobs.
3574 */
Denys Vlasenko940c7202011-03-02 04:07:14 +01003575 while (1) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003576 jp1 = *jpp;
3577#if JOBS
3578 if (!jp1 || jp1->state != JOBSTOPPED)
3579#endif
3580 break;
3581 jpp = &jp1->prev_job;
Denys Vlasenko940c7202011-03-02 04:07:14 +01003582 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003583 /* FALLTHROUGH */
3584#if JOBS
3585 case CUR_STOPPED:
3586#endif
3587 /* newly stopped job - becomes curjob */
3588 jp->prev_job = *jpp;
3589 *jpp = jp;
3590 break;
3591 }
3592}
3593
3594#if JOBS || DEBUG
3595static int
3596jobno(const struct job *jp)
3597{
3598 return jp - jobtab + 1;
3599}
3600#endif
3601
3602/*
3603 * Convert a job name to a job structure.
3604 */
Denis Vlasenko85c24712008-03-17 09:04:04 +00003605#if !JOBS
3606#define getjob(name, getctl) getjob(name)
3607#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003608static struct job *
3609getjob(const char *name, int getctl)
3610{
3611 struct job *jp;
3612 struct job *found;
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003613 const char *err_msg = "%s: no such job";
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003614 unsigned num;
3615 int c;
3616 const char *p;
3617 char *(*match)(const char *, const char *);
3618
3619 jp = curjob;
3620 p = name;
3621 if (!p)
3622 goto currentjob;
3623
3624 if (*p != '%')
3625 goto err;
3626
3627 c = *++p;
3628 if (!c)
3629 goto currentjob;
3630
3631 if (!p[1]) {
3632 if (c == '+' || c == '%') {
3633 currentjob:
3634 err_msg = "No current job";
3635 goto check;
3636 }
3637 if (c == '-') {
3638 if (jp)
3639 jp = jp->prev_job;
3640 err_msg = "No previous job";
3641 check:
3642 if (!jp)
3643 goto err;
3644 goto gotit;
3645 }
3646 }
3647
3648 if (is_number(p)) {
3649 num = atoi(p);
Denys Vlasenko07f7ea72014-09-08 17:21:52 +02003650 if (num <= njobs) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003651 jp = jobtab + num - 1;
3652 if (jp->used)
3653 goto gotit;
3654 goto err;
3655 }
3656 }
3657
3658 match = prefix;
3659 if (*p == '?') {
3660 match = strstr;
3661 p++;
3662 }
3663
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003664 found = NULL;
3665 while (jp) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003666 if (match(jp->ps[0].ps_cmd, p)) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003667 if (found)
3668 goto err;
3669 found = jp;
3670 err_msg = "%s: ambiguous";
3671 }
3672 jp = jp->prev_job;
3673 }
Denys Vlasenkoffc39202009-08-17 02:12:20 +02003674 if (!found)
3675 goto err;
3676 jp = found;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003677
3678 gotit:
3679#if JOBS
3680 err_msg = "job %s not created under job control";
3681 if (getctl && jp->jobctl == 0)
3682 goto err;
3683#endif
3684 return jp;
3685 err:
3686 ash_msg_and_raise_error(err_msg, name);
3687}
3688
3689/*
3690 * Mark a job structure as unused.
3691 */
3692static void
3693freejob(struct job *jp)
3694{
3695 struct procstat *ps;
3696 int i;
3697
3698 INT_OFF;
3699 for (i = jp->nprocs, ps = jp->ps; --i >= 0; ps++) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003700 if (ps->ps_cmd != nullstr)
3701 free(ps->ps_cmd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003702 }
3703 if (jp->ps != &jp->ps0)
3704 free(jp->ps);
3705 jp->used = 0;
3706 set_curjob(jp, CUR_DELETE);
3707 INT_ON;
3708}
3709
3710#if JOBS
3711static void
3712xtcsetpgrp(int fd, pid_t pgrp)
3713{
3714 if (tcsetpgrp(fd, pgrp))
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00003715 ash_msg_and_raise_error("can't set tty process group (%m)");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003716}
3717
3718/*
3719 * Turn job control on and off.
3720 *
3721 * Note: This code assumes that the third arg to ioctl is a character
3722 * pointer, which is true on Berkeley systems but not System V. Since
3723 * System V doesn't have job control yet, this isn't a problem now.
3724 *
3725 * Called with interrupts off.
3726 */
3727static void
3728setjobctl(int on)
3729{
3730 int fd;
3731 int pgrp;
3732
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003733 if (on == doing_jobctl || rootshell == 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003734 return;
3735 if (on) {
3736 int ofd;
3737 ofd = fd = open(_PATH_TTY, O_RDWR);
3738 if (fd < 0) {
3739 /* BTW, bash will try to open(ttyname(0)) if open("/dev/tty") fails.
3740 * That sometimes helps to acquire controlling tty.
3741 * Obviously, a workaround for bugs when someone
3742 * failed to provide a controlling tty to bash! :) */
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003743 fd = 2;
3744 while (!isatty(fd))
3745 if (--fd < 0)
3746 goto out;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003747 }
3748 fd = fcntl(fd, F_DUPFD, 10);
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003749 if (ofd >= 0)
3750 close(ofd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003751 if (fd < 0)
3752 goto out;
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003753 /* fd is a tty at this point */
Denis Vlasenko96e1b382007-09-30 23:50:48 +00003754 close_on_exec_on(fd);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003755 while (1) { /* while we are in the background */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003756 pgrp = tcgetpgrp(fd);
3757 if (pgrp < 0) {
3758 out:
3759 ash_msg("can't access tty; job control turned off");
3760 mflag = on = 0;
3761 goto close;
3762 }
3763 if (pgrp == getpgrp())
3764 break;
3765 killpg(0, SIGTTIN);
Denys Vlasenko940c7202011-03-02 04:07:14 +01003766 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003767 initialpgrp = pgrp;
3768
3769 setsignal(SIGTSTP);
3770 setsignal(SIGTTOU);
3771 setsignal(SIGTTIN);
3772 pgrp = rootpid;
3773 setpgid(0, pgrp);
3774 xtcsetpgrp(fd, pgrp);
3775 } else {
3776 /* turning job control off */
3777 fd = ttyfd;
3778 pgrp = initialpgrp;
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003779 /* was xtcsetpgrp, but this can make exiting ash
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003780 * loop forever if pty is already deleted */
Denis Vlasenko08c8c1d2007-04-28 22:39:02 +00003781 tcsetpgrp(fd, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003782 setpgid(0, pgrp);
3783 setsignal(SIGTSTP);
3784 setsignal(SIGTTOU);
3785 setsignal(SIGTTIN);
3786 close:
Denis Vlasenkoed270a52007-11-26 05:37:07 +00003787 if (fd >= 0)
3788 close(fd);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003789 fd = -1;
3790 }
3791 ttyfd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00003792 doing_jobctl = on;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003793}
3794
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003795static int FAST_FUNC
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003796killcmd(int argc, char **argv)
3797{
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003798 if (argv[1] && strcmp(argv[1], "-l") != 0) {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003799 int i = 1;
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003800 do {
3801 if (argv[i][0] == '%') {
Denys Vlasenkob12553f2011-02-21 03:22:20 +01003802 /*
3803 * "kill %N" - job kill
3804 * Converting to pgrp / pid kill
3805 */
3806 struct job *jp;
3807 char *dst;
3808 int j, n;
3809
3810 jp = getjob(argv[i], 0);
3811 /*
3812 * In jobs started under job control, we signal
3813 * entire process group by kill -PGRP_ID.
3814 * This happens, f.e., in interactive shell.
3815 *
3816 * Otherwise, we signal each child via
3817 * kill PID1 PID2 PID3.
3818 * Testcases:
3819 * sh -c 'sleep 1|sleep 1 & kill %1'
3820 * sh -c 'true|sleep 2 & sleep 1; kill %1'
3821 * sh -c 'true|sleep 1 & sleep 2; kill %1'
3822 */
3823 n = jp->nprocs; /* can't be 0 (I hope) */
3824 if (jp->jobctl)
3825 n = 1;
3826 dst = alloca(n * sizeof(int)*4);
3827 argv[i] = dst;
3828 for (j = 0; j < n; j++) {
3829 struct procstat *ps = &jp->ps[j];
3830 /* Skip non-running and not-stopped members
3831 * (i.e. dead members) of the job
3832 */
3833 if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
3834 continue;
3835 /*
3836 * kill_main has matching code to expect
3837 * leading space. Needed to not confuse
3838 * negative pids with "kill -SIGNAL_NO" syntax
3839 */
3840 dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
3841 }
3842 *dst = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003843 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003844 } while (argv[++i]);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003845 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003846 return kill_main(argc, argv);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003847}
3848
3849static void
Denys Vlasenko285ad152009-12-04 23:02:27 +01003850showpipe(struct job *jp /*, FILE *out*/)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003851{
Denys Vlasenko285ad152009-12-04 23:02:27 +01003852 struct procstat *ps;
3853 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003854
Denys Vlasenko285ad152009-12-04 23:02:27 +01003855 psend = jp->ps + jp->nprocs;
3856 for (ps = jp->ps + 1; ps < psend; ps++)
3857 printf(" | %s", ps->ps_cmd);
3858 outcslow('\n', stdout);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003859 flush_stdout_stderr();
3860}
3861
3862
3863static int
3864restartjob(struct job *jp, int mode)
3865{
3866 struct procstat *ps;
3867 int i;
3868 int status;
3869 pid_t pgid;
3870
3871 INT_OFF;
3872 if (jp->state == JOBDONE)
3873 goto out;
3874 jp->state = JOBRUNNING;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003875 pgid = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003876 if (mode == FORK_FG)
3877 xtcsetpgrp(ttyfd, pgid);
3878 killpg(pgid, SIGCONT);
3879 ps = jp->ps;
3880 i = jp->nprocs;
3881 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003882 if (WIFSTOPPED(ps->ps_status)) {
3883 ps->ps_status = -1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003884 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00003885 ps++;
3886 } while (--i);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003887 out:
3888 status = (mode == FORK_FG) ? waitforjob(jp) : 0;
3889 INT_ON;
3890 return status;
3891}
3892
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02003893static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00003894fg_bgcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003895{
3896 struct job *jp;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003897 int mode;
3898 int retval;
3899
3900 mode = (**argv == 'f') ? FORK_FG : FORK_BG;
3901 nextopt(nullstr);
3902 argv = argptr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003903 do {
3904 jp = getjob(*argv, 1);
3905 if (mode == FORK_BG) {
3906 set_curjob(jp, CUR_RUNNING);
Denys Vlasenko285ad152009-12-04 23:02:27 +01003907 printf("[%d] ", jobno(jp));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003908 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003909 out1str(jp->ps[0].ps_cmd);
3910 showpipe(jp /*, stdout*/);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003911 retval = restartjob(jp, mode);
3912 } while (*argv && *++argv);
3913 return retval;
3914}
3915#endif
3916
3917static int
3918sprint_status(char *s, int status, int sigonly)
3919{
3920 int col;
3921 int st;
3922
3923 col = 0;
3924 if (!WIFEXITED(status)) {
3925#if JOBS
3926 if (WIFSTOPPED(status))
3927 st = WSTOPSIG(status);
3928 else
3929#endif
3930 st = WTERMSIG(status);
3931 if (sigonly) {
3932 if (st == SIGINT || st == SIGPIPE)
3933 goto out;
3934#if JOBS
3935 if (WIFSTOPPED(status))
3936 goto out;
3937#endif
3938 }
3939 st &= 0x7f;
Denys Vlasenko7c6f2462011-02-14 17:17:10 +01003940//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003941 col = fmtstr(s, 32, strsignal(st));
3942 if (WCOREDUMP(status)) {
3943 col += fmtstr(s + col, 16, " (core dumped)");
3944 }
3945 } else if (!sigonly) {
3946 st = WEXITSTATUS(status);
3947 if (st)
3948 col = fmtstr(s, 16, "Done(%d)", st);
3949 else
3950 col = fmtstr(s, 16, "Done");
3951 }
3952 out:
3953 return col;
3954}
3955
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003956static int
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00003957dowait(int wait_flags, struct job *job)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003958{
3959 int pid;
3960 int status;
3961 struct job *jp;
3962 struct job *thisjob;
3963 int state;
3964
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00003965 TRACE(("dowait(0x%x) called\n", wait_flags));
3966
3967 /* Do a wait system call. If job control is compiled in, we accept
3968 * stopped processes. wait_flags may have WNOHANG, preventing blocking.
3969 * NB: _not_ safe_waitpid, we need to detect EINTR */
Denys Vlasenko285ad152009-12-04 23:02:27 +01003970 if (doing_jobctl)
3971 wait_flags |= WUNTRACED;
3972 pid = waitpid(-1, &status, wait_flags);
Denis Vlasenkob21f3792009-03-19 23:09:58 +00003973 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3974 pid, status, errno, strerror(errno)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003975 if (pid <= 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003976 return pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00003977
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003978 INT_OFF;
3979 thisjob = NULL;
3980 for (jp = curjob; jp; jp = jp->prev_job) {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003981 struct procstat *ps;
3982 struct procstat *psend;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003983 if (jp->state == JOBDONE)
3984 continue;
3985 state = JOBDONE;
Denys Vlasenko285ad152009-12-04 23:02:27 +01003986 ps = jp->ps;
3987 psend = ps + jp->nprocs;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003988 do {
Denys Vlasenko285ad152009-12-04 23:02:27 +01003989 if (ps->ps_pid == pid) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003990 TRACE(("Job %d: changing status of proc %d "
3991 "from 0x%x to 0x%x\n",
Denys Vlasenko285ad152009-12-04 23:02:27 +01003992 jobno(jp), pid, ps->ps_status, status));
3993 ps->ps_status = status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003994 thisjob = jp;
3995 }
Denys Vlasenko285ad152009-12-04 23:02:27 +01003996 if (ps->ps_status == -1)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00003997 state = JOBRUNNING;
3998#if JOBS
3999 if (state == JOBRUNNING)
4000 continue;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004001 if (WIFSTOPPED(ps->ps_status)) {
4002 jp->stopstatus = ps->ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004003 state = JOBSTOPPED;
4004 }
4005#endif
Denys Vlasenko285ad152009-12-04 23:02:27 +01004006 } while (++ps < psend);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004007 if (thisjob)
4008 goto gotjob;
4009 }
4010#if JOBS
4011 if (!WIFSTOPPED(status))
4012#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004013 jobless--;
4014 goto out;
4015
4016 gotjob:
4017 if (state != JOBRUNNING) {
4018 thisjob->changed = 1;
4019
4020 if (thisjob->state != state) {
4021 TRACE(("Job %d: changing state from %d to %d\n",
4022 jobno(thisjob), thisjob->state, state));
4023 thisjob->state = state;
4024#if JOBS
4025 if (state == JOBSTOPPED) {
4026 set_curjob(thisjob, CUR_STOPPED);
4027 }
4028#endif
4029 }
4030 }
4031
4032 out:
4033 INT_ON;
4034
4035 if (thisjob && thisjob == job) {
4036 char s[48 + 1];
4037 int len;
4038
4039 len = sprint_status(s, status, 1);
4040 if (len) {
4041 s[len] = '\n';
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004042 s[len + 1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004043 out2str(s);
4044 }
4045 }
4046 return pid;
4047}
4048
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004049static int
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004050blocking_wait_with_raise_on_sig(void)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004051{
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004052 pid_t pid = dowait(DOWAIT_BLOCK, NULL);
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004053 if (pid <= 0 && pending_sig)
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004054 raise_exception(EXSIG);
4055 return pid;
4056}
4057
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004058#if JOBS
4059static void
4060showjob(FILE *out, struct job *jp, int mode)
4061{
4062 struct procstat *ps;
4063 struct procstat *psend;
4064 int col;
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004065 int indent_col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004066 char s[80];
4067
4068 ps = jp->ps;
4069
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004070 if (mode & SHOW_ONLY_PGID) { /* jobs -p */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004071 /* just output process (group) id of pipeline */
Denys Vlasenko285ad152009-12-04 23:02:27 +01004072 fprintf(out, "%d\n", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004073 return;
4074 }
4075
4076 col = fmtstr(s, 16, "[%d] ", jobno(jp));
Denis Vlasenko40ba9982007-07-14 00:48:29 +00004077 indent_col = col;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004078
4079 if (jp == curjob)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004080 s[col - 3] = '+';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004081 else if (curjob && jp == curjob->prev_job)
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004082 s[col - 3] = '-';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004083
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004084 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004085 col += fmtstr(s + col, 16, "%d ", ps->ps_pid);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004086
4087 psend = ps + jp->nprocs;
4088
4089 if (jp->state == JOBRUNNING) {
4090 strcpy(s + col, "Running");
4091 col += sizeof("Running") - 1;
4092 } else {
Denys Vlasenko285ad152009-12-04 23:02:27 +01004093 int status = psend[-1].ps_status;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004094 if (jp->state == JOBSTOPPED)
4095 status = jp->stopstatus;
4096 col += sprint_status(s + col, status, 0);
4097 }
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004098 /* By now, "[JOBID]* [maybe PID] STATUS" is printed */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004099
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004100 /* This loop either prints "<cmd1> | <cmd2> | <cmd3>" line
4101 * or prints several "PID | <cmdN>" lines,
4102 * depending on SHOW_PIDS bit.
4103 * We do not print status of individual processes
4104 * between PID and <cmdN>. bash does it, but not very well:
4105 * first line shows overall job status, not process status,
4106 * making it impossible to know 1st process status.
4107 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004108 goto start;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004109 do {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004110 /* for each process */
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004111 s[0] = '\0';
4112 col = 33;
4113 if (mode & SHOW_PIDS)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004114 col = fmtstr(s, 48, "\n%*c%d ", indent_col, ' ', ps->ps_pid) - 1;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004115 start:
Denys Vlasenko285ad152009-12-04 23:02:27 +01004116 fprintf(out, "%s%*c%s%s",
4117 s,
4118 33 - col >= 0 ? 33 - col : 0, ' ',
4119 ps == jp->ps ? "" : "| ",
4120 ps->ps_cmd
4121 );
4122 } while (++ps != psend);
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004123 outcslow('\n', out);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004124
4125 jp->changed = 0;
4126
4127 if (jp->state == JOBDONE) {
4128 TRACE(("showjob: freeing job %d\n", jobno(jp)));
4129 freejob(jp);
4130 }
4131}
4132
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004133/*
4134 * Print a list of jobs. If "change" is nonzero, only print jobs whose
4135 * statuses have changed since the last call to showjobs.
4136 */
4137static void
4138showjobs(FILE *out, int mode)
4139{
4140 struct job *jp;
4141
Denys Vlasenko883cea42009-07-11 15:31:59 +02004142 TRACE(("showjobs(0x%x) called\n", mode));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004143
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004144 /* Handle all finished jobs */
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004145 while (dowait(DOWAIT_NONBLOCK, NULL) > 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004146 continue;
4147
4148 for (jp = curjob; jp; jp = jp->prev_job) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004149 if (!(mode & SHOW_CHANGED) || jp->changed) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004150 showjob(out, jp, mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004151 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004152 }
4153}
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004154
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004155static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004156jobscmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004157{
4158 int mode, m;
4159
4160 mode = 0;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004161 while ((m = nextopt("lp")) != '\0') {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004162 if (m == 'l')
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004163 mode |= SHOW_PIDS;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004164 else
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004165 mode |= SHOW_ONLY_PGID;
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004166 }
4167
4168 argv = argptr;
4169 if (*argv) {
4170 do
Denys Vlasenkoa12af2d2009-08-23 22:10:04 +02004171 showjob(stdout, getjob(*argv, 0), mode);
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004172 while (*++argv);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004173 } else {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004174 showjobs(stdout, mode);
Denys Vlasenko285ad152009-12-04 23:02:27 +01004175 }
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004176
4177 return 0;
4178}
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004179#endif /* JOBS */
4180
Michael Abbott359da5e2009-12-04 23:03:29 +01004181/* Called only on finished or stopped jobs (no members are running) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004182static int
4183getstatus(struct job *job)
4184{
4185 int status;
4186 int retval;
Michael Abbott359da5e2009-12-04 23:03:29 +01004187 struct procstat *ps;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004188
Michael Abbott359da5e2009-12-04 23:03:29 +01004189 /* Fetch last member's status */
4190 ps = job->ps + job->nprocs - 1;
4191 status = ps->ps_status;
4192 if (pipefail) {
4193 /* "set -o pipefail" mode: use last _nonzero_ status */
4194 while (status == 0 && --ps >= job->ps)
4195 status = ps->ps_status;
4196 }
4197
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004198 retval = WEXITSTATUS(status);
4199 if (!WIFEXITED(status)) {
4200#if JOBS
4201 retval = WSTOPSIG(status);
4202 if (!WIFSTOPPED(status))
4203#endif
4204 {
4205 /* XXX: limits number of signals */
4206 retval = WTERMSIG(status);
4207#if JOBS
4208 if (retval == SIGINT)
4209 job->sigint = 1;
4210#endif
4211 }
4212 retval += 128;
4213 }
Denys Vlasenko883cea42009-07-11 15:31:59 +02004214 TRACE(("getstatus: job %d, nproc %d, status 0x%x, retval 0x%x\n",
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004215 jobno(job), job->nprocs, status, retval));
4216 return retval;
4217}
4218
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02004219static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00004220waitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004221{
4222 struct job *job;
4223 int retval;
4224 struct job *jp;
4225
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004226 if (pending_sig)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004227 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004228
4229 nextopt(nullstr);
4230 retval = 0;
4231
4232 argv = argptr;
4233 if (!*argv) {
4234 /* wait for all jobs */
4235 for (;;) {
4236 jp = curjob;
4237 while (1) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004238 if (!jp) /* no running procs */
4239 goto ret;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004240 if (jp->state == JOBRUNNING)
4241 break;
4242 jp->waited = 1;
4243 jp = jp->prev_job;
4244 }
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004245 blocking_wait_with_raise_on_sig();
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004246 /* man bash:
4247 * "When bash is waiting for an asynchronous command via
4248 * the wait builtin, the reception of a signal for which a trap
4249 * has been set will cause the wait builtin to return immediately
4250 * with an exit status greater than 128, immediately after which
4251 * the trap is executed."
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004252 *
4253 * blocking_wait_with_raise_on_sig raises signal handlers
4254 * if it gets no pid (pid < 0). However,
4255 * if child sends us a signal *and immediately exits*,
4256 * blocking_wait_with_raise_on_sig gets pid > 0
4257 * and does not handle pending_sig. Check this case: */
4258 if (pending_sig)
4259 raise_exception(EXSIG);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004260 }
4261 }
4262
4263 retval = 127;
4264 do {
4265 if (**argv != '%') {
4266 pid_t pid = number(*argv);
4267 job = curjob;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004268 while (1) {
4269 if (!job)
4270 goto repeat;
Denys Vlasenko285ad152009-12-04 23:02:27 +01004271 if (job->ps[job->nprocs - 1].ps_pid == pid)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004272 break;
4273 job = job->prev_job;
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004274 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004275 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004276 job = getjob(*argv, 0);
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004277 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004278 /* loop until process terminated or stopped */
4279 while (job->state == JOBRUNNING)
Denys Vlasenko7c1ed9f2010-05-17 04:42:40 +02004280 blocking_wait_with_raise_on_sig();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004281 job->waited = 1;
4282 retval = getstatus(job);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004283 repeat: ;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004284 } while (*++argv);
4285
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004286 ret:
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004287 return retval;
4288}
4289
4290static struct job *
4291growjobtab(void)
4292{
4293 size_t len;
4294 ptrdiff_t offset;
4295 struct job *jp, *jq;
4296
4297 len = njobs * sizeof(*jp);
4298 jq = jobtab;
4299 jp = ckrealloc(jq, len + 4 * sizeof(*jp));
4300
4301 offset = (char *)jp - (char *)jq;
4302 if (offset) {
4303 /* Relocate pointers */
4304 size_t l = len;
4305
4306 jq = (struct job *)((char *)jq + l);
4307 while (l) {
4308 l -= sizeof(*jp);
4309 jq--;
4310#define joff(p) ((struct job *)((char *)(p) + l))
4311#define jmove(p) (p) = (void *)((char *)(p) + offset)
4312 if (joff(jp)->ps == &jq->ps0)
4313 jmove(joff(jp)->ps);
4314 if (joff(jp)->prev_job)
4315 jmove(joff(jp)->prev_job);
4316 }
4317 if (curjob)
4318 jmove(curjob);
4319#undef joff
4320#undef jmove
4321 }
4322
4323 njobs += 4;
4324 jobtab = jp;
4325 jp = (struct job *)((char *)jp + len);
4326 jq = jp + 3;
4327 do {
4328 jq->used = 0;
4329 } while (--jq >= jp);
4330 return jp;
4331}
4332
4333/*
4334 * Return a new job structure.
4335 * Called with interrupts off.
4336 */
4337static struct job *
Denis Vlasenko68404f12008-03-17 09:00:54 +00004338makejob(/*union node *node,*/ int nprocs)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004339{
4340 int i;
4341 struct job *jp;
4342
4343 for (i = njobs, jp = jobtab; ; jp++) {
4344 if (--i < 0) {
4345 jp = growjobtab();
4346 break;
4347 }
4348 if (jp->used == 0)
4349 break;
4350 if (jp->state != JOBDONE || !jp->waited)
4351 continue;
4352#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004353 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004354 continue;
4355#endif
4356 freejob(jp);
4357 break;
4358 }
4359 memset(jp, 0, sizeof(*jp));
4360#if JOBS
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +00004361 /* jp->jobctl is a bitfield.
4362 * "jp->jobctl |= jobctl" likely to give awful code */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004363 if (doing_jobctl)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004364 jp->jobctl = 1;
4365#endif
4366 jp->prev_job = curjob;
4367 curjob = jp;
4368 jp->used = 1;
4369 jp->ps = &jp->ps0;
4370 if (nprocs > 1) {
4371 jp->ps = ckmalloc(nprocs * sizeof(struct procstat));
4372 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00004373 TRACE(("makejob(%d) returns %%%d\n", nprocs,
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004374 jobno(jp)));
4375 return jp;
4376}
4377
4378#if JOBS
4379/*
4380 * Return a string identifying a command (to be printed by the
4381 * jobs command).
4382 */
4383static char *cmdnextc;
4384
4385static void
4386cmdputs(const char *s)
4387{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004388 static const char vstype[VSTYPE + 1][3] = {
4389 "", "}", "-", "+", "?", "=",
4390 "%", "%%", "#", "##"
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00004391 IF_ASH_BASH_COMPAT(, ":", "/", "//")
Denis Vlasenko92e13c22008-03-25 01:17:40 +00004392 };
4393
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004394 const char *p, *str;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004395 char cc[2];
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004396 char *nextc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01004397 unsigned char c;
4398 unsigned char subtype = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004399 int quoted = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004400
Denys Vlasenko46a14772009-12-10 21:27:13 +01004401 cc[1] = '\0';
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004402 nextc = makestrspace((strlen(s) + 1) * 8, cmdnextc);
4403 p = s;
Denys Vlasenko46a14772009-12-10 21:27:13 +01004404 while ((c = *p++) != '\0') {
Denis Vlasenkoef527f52008-06-23 01:52:30 +00004405 str = NULL;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004406 switch (c) {
4407 case CTLESC:
4408 c = *p++;
4409 break;
4410 case CTLVAR:
4411 subtype = *p++;
4412 if ((subtype & VSTYPE) == VSLENGTH)
4413 str = "${#";
4414 else
4415 str = "${";
4416 if (!(subtype & VSQUOTE) == !(quoted & 1))
4417 goto dostr;
4418 quoted ^= 1;
4419 c = '"';
4420 break;
4421 case CTLENDVAR:
4422 str = "\"}" + !(quoted & 1);
4423 quoted >>= 1;
4424 subtype = 0;
4425 goto dostr;
4426 case CTLBACKQ:
4427 str = "$(...)";
4428 goto dostr;
4429 case CTLBACKQ+CTLQUOTE:
4430 str = "\"$(...)\"";
4431 goto dostr;
Mike Frysinger98c52642009-04-02 10:02:37 +00004432#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004433 case CTLARI:
4434 str = "$((";
4435 goto dostr;
4436 case CTLENDARI:
4437 str = "))";
4438 goto dostr;
4439#endif
4440 case CTLQUOTEMARK:
4441 quoted ^= 1;
4442 c = '"';
4443 break;
4444 case '=':
4445 if (subtype == 0)
4446 break;
4447 if ((subtype & VSTYPE) != VSNORMAL)
4448 quoted <<= 1;
4449 str = vstype[subtype & VSTYPE];
4450 if (subtype & VSNUL)
4451 c = ':';
4452 else
4453 goto checkstr;
4454 break;
4455 case '\'':
4456 case '\\':
4457 case '"':
4458 case '$':
4459 /* These can only happen inside quotes */
4460 cc[0] = c;
4461 str = cc;
4462 c = '\\';
4463 break;
4464 default:
4465 break;
4466 }
4467 USTPUTC(c, nextc);
4468 checkstr:
4469 if (!str)
4470 continue;
4471 dostr:
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02004472 while ((c = *str++) != '\0') {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004473 USTPUTC(c, nextc);
4474 }
Denys Vlasenko46a14772009-12-10 21:27:13 +01004475 } /* while *p++ not NUL */
4476
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004477 if (quoted & 1) {
4478 USTPUTC('"', nextc);
4479 }
4480 *nextc = 0;
4481 cmdnextc = nextc;
4482}
4483
4484/* cmdtxt() and cmdlist() call each other */
4485static void cmdtxt(union node *n);
4486
4487static void
4488cmdlist(union node *np, int sep)
4489{
4490 for (; np; np = np->narg.next) {
4491 if (!sep)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004492 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004493 cmdtxt(np);
4494 if (sep && np->narg.next)
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00004495 cmdputs(" ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004496 }
4497}
4498
4499static void
4500cmdtxt(union node *n)
4501{
4502 union node *np;
4503 struct nodelist *lp;
4504 const char *p;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004505
4506 if (!n)
4507 return;
4508 switch (n->type) {
4509 default:
4510#if DEBUG
4511 abort();
4512#endif
4513 case NPIPE:
4514 lp = n->npipe.cmdlist;
4515 for (;;) {
4516 cmdtxt(lp->n);
4517 lp = lp->next;
4518 if (!lp)
4519 break;
4520 cmdputs(" | ");
4521 }
4522 break;
4523 case NSEMI:
4524 p = "; ";
4525 goto binop;
4526 case NAND:
4527 p = " && ";
4528 goto binop;
4529 case NOR:
4530 p = " || ";
4531 binop:
4532 cmdtxt(n->nbinary.ch1);
4533 cmdputs(p);
4534 n = n->nbinary.ch2;
4535 goto donode;
4536 case NREDIR:
4537 case NBACKGND:
4538 n = n->nredir.n;
4539 goto donode;
4540 case NNOT:
4541 cmdputs("!");
4542 n = n->nnot.com;
4543 donode:
4544 cmdtxt(n);
4545 break;
4546 case NIF:
4547 cmdputs("if ");
4548 cmdtxt(n->nif.test);
4549 cmdputs("; then ");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004550 if (n->nif.elsepart) {
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004551 cmdtxt(n->nif.ifpart);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004552 cmdputs("; else ");
4553 n = n->nif.elsepart;
Denys Vlasenko7cee00e2009-07-24 01:08:03 +02004554 } else {
4555 n = n->nif.ifpart;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004556 }
4557 p = "; fi";
4558 goto dotail;
4559 case NSUBSHELL:
4560 cmdputs("(");
4561 n = n->nredir.n;
4562 p = ")";
4563 goto dotail;
4564 case NWHILE:
4565 p = "while ";
4566 goto until;
4567 case NUNTIL:
4568 p = "until ";
4569 until:
4570 cmdputs(p);
4571 cmdtxt(n->nbinary.ch1);
4572 n = n->nbinary.ch2;
4573 p = "; done";
4574 dodo:
4575 cmdputs("; do ");
4576 dotail:
4577 cmdtxt(n);
4578 goto dotail2;
4579 case NFOR:
4580 cmdputs("for ");
4581 cmdputs(n->nfor.var);
4582 cmdputs(" in ");
4583 cmdlist(n->nfor.args, 1);
4584 n = n->nfor.body;
4585 p = "; done";
4586 goto dodo;
4587 case NDEFUN:
4588 cmdputs(n->narg.text);
4589 p = "() { ... }";
4590 goto dotail2;
4591 case NCMD:
4592 cmdlist(n->ncmd.args, 1);
4593 cmdlist(n->ncmd.redirect, 0);
4594 break;
4595 case NARG:
4596 p = n->narg.text;
4597 dotail2:
4598 cmdputs(p);
4599 break;
4600 case NHERE:
4601 case NXHERE:
4602 p = "<<...";
4603 goto dotail2;
4604 case NCASE:
4605 cmdputs("case ");
4606 cmdputs(n->ncase.expr->narg.text);
4607 cmdputs(" in ");
4608 for (np = n->ncase.cases; np; np = np->nclist.next) {
4609 cmdtxt(np->nclist.pattern);
4610 cmdputs(") ");
4611 cmdtxt(np->nclist.body);
4612 cmdputs(";; ");
4613 }
4614 p = "esac";
4615 goto dotail2;
4616 case NTO:
4617 p = ">";
4618 goto redir;
4619 case NCLOBBER:
4620 p = ">|";
4621 goto redir;
4622 case NAPPEND:
4623 p = ">>";
4624 goto redir;
Denis Vlasenko559691a2008-10-05 18:39:31 +00004625#if ENABLE_ASH_BASH_COMPAT
4626 case NTO2:
4627#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004628 case NTOFD:
4629 p = ">&";
4630 goto redir;
4631 case NFROM:
4632 p = "<";
4633 goto redir;
4634 case NFROMFD:
4635 p = "<&";
4636 goto redir;
4637 case NFROMTO:
4638 p = "<>";
4639 redir:
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004640 cmdputs(utoa(n->nfile.fd));
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004641 cmdputs(p);
4642 if (n->type == NTOFD || n->type == NFROMFD) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00004643 cmdputs(utoa(n->ndup.dupfd));
4644 break;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004645 }
4646 n = n->nfile.fname;
4647 goto donode;
4648 }
4649}
4650
4651static char *
4652commandtext(union node *n)
4653{
4654 char *name;
4655
4656 STARTSTACKSTR(cmdnextc);
4657 cmdtxt(n);
4658 name = stackblock();
4659 TRACE(("commandtext: name %p, end %p\n\t\"%s\"\n",
4660 name, cmdnextc, cmdnextc));
4661 return ckstrdup(name);
4662}
4663#endif /* JOBS */
4664
4665/*
4666 * Fork off a subshell. If we are doing job control, give the subshell its
4667 * own process group. Jp is a job structure that the job is to be added to.
4668 * N is the command that will be evaluated by the child. Both jp and n may
4669 * be NULL. The mode parameter can be one of the following:
4670 * FORK_FG - Fork off a foreground process.
4671 * FORK_BG - Fork off a background process.
4672 * FORK_NOJOB - Like FORK_FG, but don't give the process its own
4673 * process group even if job control is on.
4674 *
4675 * When job control is turned off, background processes have their standard
4676 * input redirected to /dev/null (except for the second and later processes
4677 * in a pipeline).
4678 *
4679 * Called with interrupts off.
4680 */
4681/*
4682 * Clear traps on a fork.
4683 */
4684static void
4685clear_traps(void)
4686{
4687 char **tp;
4688
4689 for (tp = trap; tp < &trap[NSIG]; tp++) {
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004690 if (*tp && **tp) { /* trap not NULL or "" (SIG_IGN) */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004691 INT_OFF;
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004692 if (trap_ptr == trap)
4693 free(*tp);
4694 /* else: it "belongs" to trap_ptr vector, don't free */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004695 *tp = NULL;
Denys Vlasenko0800e3a2009-09-24 03:09:26 +02004696 if ((tp - trap) != 0)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004697 setsignal(tp - trap);
4698 INT_ON;
4699 }
4700 }
Alexander Shishkinccb97712010-07-25 13:07:39 +02004701 may_have_traps = 0;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004702}
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004703
4704/* Lives far away from here, needed for forkchild */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004705static void closescript(void);
Denis Vlasenko41770222007-10-07 18:02:52 +00004706
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004707/* Called after fork(), in child */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004708static NOINLINE void
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004709forkchild(struct job *jp, union node *n, int mode)
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004710{
4711 int oldlvl;
4712
4713 TRACE(("Child shell %d\n", getpid()));
4714 oldlvl = shlvl;
4715 shlvl++;
4716
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004717 /* man bash: "Non-builtin commands run by bash have signal handlers
4718 * set to the values inherited by the shell from its parent".
4719 * Do we do it correctly? */
4720
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004721 closescript();
Denys Vlasenko844f9902009-09-23 03:25:52 +02004722
4723 if (mode == FORK_NOJOB /* is it `xxx` ? */
4724 && n && n->type == NCMD /* is it single cmd? */
4725 /* && n->ncmd.args->type == NARG - always true? */
Denys Vlasenko74269202010-02-21 01:26:42 +01004726 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "trap") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004727 && n->ncmd.args->narg.next == NULL /* "trap" with no arguments */
4728 /* && n->ncmd.args->narg.backquote == NULL - do we need to check this? */
4729 ) {
4730 TRACE(("Trap hack\n"));
4731 /* Awful hack for `trap` or $(trap).
4732 *
4733 * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
4734 * contains an example where "trap" is executed in a subshell:
4735 *
4736 * save_traps=$(trap)
4737 * ...
4738 * eval "$save_traps"
4739 *
4740 * Standard does not say that "trap" in subshell shall print
4741 * parent shell's traps. It only says that its output
4742 * must have suitable form, but then, in the above example
4743 * (which is not supposed to be normative), it implies that.
4744 *
4745 * bash (and probably other shell) does implement it
4746 * (traps are reset to defaults, but "trap" still shows them),
4747 * but as a result, "trap" logic is hopelessly messed up:
4748 *
4749 * # trap
4750 * trap -- 'echo Ho' SIGWINCH <--- we have a handler
4751 * # (trap) <--- trap is in subshell - no output (correct, traps are reset)
4752 * # true | trap <--- trap is in subshell - no output (ditto)
4753 * # echo `true | trap` <--- in subshell - output (but traps are reset!)
4754 * trap -- 'echo Ho' SIGWINCH
4755 * # echo `(trap)` <--- in subshell in subshell - output
4756 * trap -- 'echo Ho' SIGWINCH
4757 * # echo `true | (trap)` <--- in subshell in subshell in subshell - output!
4758 * trap -- 'echo Ho' SIGWINCH
4759 *
4760 * The rules when to forget and when to not forget traps
4761 * get really complex and nonsensical.
4762 *
4763 * Our solution: ONLY bare $(trap) or `trap` is special.
4764 */
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004765 /* Save trap handler strings for trap builtin to print */
Denys Vlasenko21d87d42009-09-25 00:06:51 +02004766 trap_ptr = memcpy(xmalloc(sizeof(trap)), trap, sizeof(trap));
Denys Vlasenko8f88d852009-09-25 12:12:53 +02004767 /* Fall through into clearing traps */
Denys Vlasenko844f9902009-09-23 03:25:52 +02004768 }
Denys Vlasenkoe305c282009-09-25 02:12:27 +02004769 clear_traps();
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004770#if JOBS
4771 /* do job control only in root shell */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004772 doing_jobctl = 0;
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004773 if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004774 pid_t pgrp;
4775
4776 if (jp->nprocs == 0)
4777 pgrp = getpid();
4778 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004779 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004780 /* this can fail because we are doing it in the parent also */
4781 setpgid(0, pgrp);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004782 if (mode == FORK_FG)
4783 xtcsetpgrp(ttyfd, pgrp);
4784 setsignal(SIGTSTP);
4785 setsignal(SIGTTOU);
4786 } else
4787#endif
4788 if (mode == FORK_BG) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004789 /* man bash: "When job control is not in effect,
4790 * asynchronous commands ignore SIGINT and SIGQUIT" */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004791 ignoresig(SIGINT);
4792 ignoresig(SIGQUIT);
4793 if (jp->nprocs == 0) {
4794 close(0);
4795 if (open(bb_dev_null, O_RDONLY) != 0)
Denis Vlasenko9604e1b2009-03-03 18:47:56 +00004796 ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004797 }
4798 }
Denys Vlasenkob12553f2011-02-21 03:22:20 +01004799 if (oldlvl == 0) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004800 if (iflag) { /* why if iflag only? */
4801 setsignal(SIGINT);
4802 setsignal(SIGTERM);
4803 }
4804 /* man bash:
4805 * "In all cases, bash ignores SIGQUIT. Non-builtin
4806 * commands run by bash have signal handlers
4807 * set to the values inherited by the shell
4808 * from its parent".
4809 * Take care of the second rule: */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004810 setsignal(SIGQUIT);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004811 }
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004812#if JOBS
Denys Vlasenko844f9902009-09-23 03:25:52 +02004813 if (n && n->type == NCMD
Denys Vlasenko74269202010-02-21 01:26:42 +01004814 && n->ncmd.args && strcmp(n->ncmd.args->narg.text, "jobs") == 0
Denys Vlasenko844f9902009-09-23 03:25:52 +02004815 ) {
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004816 TRACE(("Job hack\n"));
Denys Vlasenko844f9902009-09-23 03:25:52 +02004817 /* "jobs": we do not want to clear job list for it,
4818 * instead we remove only _its_ own_ job from job list.
4819 * This makes "jobs .... | cat" more useful.
4820 */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004821 freejob(curjob);
4822 return;
4823 }
4824#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004825 for (jp = curjob; jp; jp = jp->prev_job)
4826 freejob(jp);
4827 jobless = 0;
4828}
4829
Denis Vlasenkobdc406d2007-07-15 01:13:25 +00004830/* Called after fork(), in parent */
Denis Vlasenko85c24712008-03-17 09:04:04 +00004831#if !JOBS
4832#define forkparent(jp, n, mode, pid) forkparent(jp, mode, pid)
4833#endif
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004834static void
4835forkparent(struct job *jp, union node *n, int mode, pid_t pid)
4836{
4837 TRACE(("In parent shell: child = %d\n", pid));
4838 if (!jp) {
Denis Vlasenko36fc3cd2008-01-29 09:23:49 +00004839 while (jobless && dowait(DOWAIT_NONBLOCK, NULL) > 0)
4840 continue;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004841 jobless++;
4842 return;
4843 }
4844#if JOBS
4845 if (mode != FORK_NOJOB && jp->jobctl) {
4846 int pgrp;
4847
4848 if (jp->nprocs == 0)
4849 pgrp = pid;
4850 else
Denys Vlasenko285ad152009-12-04 23:02:27 +01004851 pgrp = jp->ps[0].ps_pid;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004852 /* This can fail because we are doing it in the child also */
4853 setpgid(pid, pgrp);
4854 }
4855#endif
4856 if (mode == FORK_BG) {
4857 backgndpid = pid; /* set $! */
4858 set_curjob(jp, CUR_RUNNING);
4859 }
4860 if (jp) {
4861 struct procstat *ps = &jp->ps[jp->nprocs++];
Denys Vlasenko285ad152009-12-04 23:02:27 +01004862 ps->ps_pid = pid;
4863 ps->ps_status = -1;
4864 ps->ps_cmd = nullstr;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004865#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +00004866 if (doing_jobctl && n)
Denys Vlasenko285ad152009-12-04 23:02:27 +01004867 ps->ps_cmd = commandtext(n);
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004868#endif
4869 }
4870}
4871
4872static int
4873forkshell(struct job *jp, union node *n, int mode)
4874{
4875 int pid;
4876
4877 TRACE(("forkshell(%%%d, %p, %d) called\n", jobno(jp), n, mode));
4878 pid = fork();
4879 if (pid < 0) {
4880 TRACE(("Fork failed, errno=%d", errno));
4881 if (jp)
4882 freejob(jp);
Denis Vlasenkofa0b56d2008-07-01 16:09:07 +00004883 ash_msg_and_raise_error("can't fork");
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004884 }
Denys Vlasenko76ace252009-10-12 15:25:01 +02004885 if (pid == 0) {
4886 CLEAR_RANDOM_T(&random_gen); /* or else $RANDOM repeats in child */
Denys Vlasenkoe56f22a2009-07-24 00:16:59 +02004887 forkchild(jp, n, mode);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004888 } else {
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004889 forkparent(jp, n, mode, pid);
Denys Vlasenko76ace252009-10-12 15:25:01 +02004890 }
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004891 return pid;
4892}
4893
4894/*
4895 * Wait for job to finish.
4896 *
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004897 * Under job control we have the problem that while a child process
4898 * is running interrupts generated by the user are sent to the child
4899 * but not to the shell. This means that an infinite loop started by
4900 * an interactive user may be hard to kill. With job control turned off,
4901 * an interactive user may place an interactive program inside a loop.
4902 * If the interactive program catches interrupts, the user doesn't want
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004903 * these interrupts to also abort the loop. The approach we take here
4904 * is to have the shell ignore interrupt signals while waiting for a
4905 * foreground process to terminate, and then send itself an interrupt
4906 * signal if the child process was terminated by an interrupt signal.
4907 * Unfortunately, some programs want to do a bit of cleanup and then
4908 * exit on interrupt; unless these processes terminate themselves by
4909 * sending a signal to themselves (instead of calling exit) they will
4910 * confuse this approach.
4911 *
4912 * Called with interrupts off.
4913 */
4914static int
4915waitforjob(struct job *jp)
4916{
4917 int st;
4918
4919 TRACE(("waitforjob(%%%d) called\n", jobno(jp)));
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004920
4921 INT_OFF;
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004922 while (jp->state == JOBRUNNING) {
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004923 /* In non-interactive shells, we _can_ get
4924 * a keyboard signal here and be EINTRed,
4925 * but we just loop back, waiting for command to complete.
4926 *
4927 * man bash:
4928 * "If bash is waiting for a command to complete and receives
4929 * a signal for which a trap has been set, the trap
4930 * will not be executed until the command completes."
4931 *
4932 * Reality is that even if trap is not set, bash
4933 * will not act on the signal until command completes.
4934 * Try this. sleep5intoff.c:
4935 * #include <signal.h>
4936 * #include <unistd.h>
4937 * int main() {
4938 * sigset_t set;
4939 * sigemptyset(&set);
4940 * sigaddset(&set, SIGINT);
4941 * sigaddset(&set, SIGQUIT);
4942 * sigprocmask(SIG_BLOCK, &set, NULL);
4943 * sleep(5);
4944 * return 0;
4945 * }
4946 * $ bash -c './sleep5intoff; echo hi'
4947 * ^C^C^C^C <--- pressing ^C once a second
4948 * $ _
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004949 * $ bash -c './sleep5intoff; echo hi'
4950 * ^\^\^\^\hi <--- pressing ^\ (SIGQUIT)
4951 * $ _
4952 */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004953 dowait(DOWAIT_BLOCK, jp);
4954 }
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00004955 INT_ON;
4956
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004957 st = getstatus(jp);
4958#if JOBS
4959 if (jp->jobctl) {
4960 xtcsetpgrp(ttyfd, rootpid);
4961 /*
4962 * This is truly gross.
4963 * If we're doing job control, then we did a TIOCSPGRP which
4964 * caused us (the shell) to no longer be in the controlling
4965 * session -- so we wouldn't have seen any ^C/SIGINT. So, we
4966 * intuit from the subprocess exit status whether a SIGINT
4967 * occurred, and if so interrupt ourselves. Yuck. - mycroft
4968 */
Denis Vlasenko991a1da2008-02-10 19:02:53 +00004969 if (jp->sigint) /* TODO: do the same with all signals */
4970 raise(SIGINT); /* ... by raise(jp->sig) instead? */
Denis Vlasenkoa8915072007-02-23 21:10:06 +00004971 }
4972 if (jp->state == JOBDONE)
4973#endif
4974 freejob(jp);
4975 return st;
4976}
4977
4978/*
4979 * return 1 if there are stopped jobs, otherwise 0
4980 */
4981static int
4982stoppedjobs(void)
4983{
4984 struct job *jp;
4985 int retval;
4986
4987 retval = 0;
4988 if (job_warning)
4989 goto out;
4990 jp = curjob;
4991 if (jp && jp->state == JOBSTOPPED) {
4992 out2str("You have stopped jobs.\n");
4993 job_warning = 2;
4994 retval++;
4995 }
4996 out:
4997 return retval;
4998}
4999
5000
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005001/* ============ redir.c
5002 *
5003 * Code for dealing with input/output redirection.
5004 */
5005
Denys Vlasenko8d0e0cd2011-01-25 23:21:46 +01005006#undef EMPTY
5007#undef CLOSED
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005008#define EMPTY -2 /* marks an unused slot in redirtab */
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005009#define CLOSED -3 /* marks a slot of previously-closed fd */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005010
5011/*
5012 * Open a file in noclobber mode.
5013 * The code was copied from bash.
5014 */
5015static int
5016noclobberopen(const char *fname)
5017{
5018 int r, fd;
5019 struct stat finfo, finfo2;
5020
5021 /*
5022 * If the file exists and is a regular file, return an error
5023 * immediately.
5024 */
5025 r = stat(fname, &finfo);
5026 if (r == 0 && S_ISREG(finfo.st_mode)) {
5027 errno = EEXIST;
5028 return -1;
5029 }
5030
5031 /*
5032 * If the file was not present (r != 0), make sure we open it
5033 * exclusively so that if it is created before we open it, our open
5034 * will fail. Make sure that we do not truncate an existing file.
5035 * Note that we don't turn on O_EXCL unless the stat failed -- if the
5036 * file was not a regular file, we leave O_EXCL off.
5037 */
5038 if (r != 0)
5039 return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
5040 fd = open(fname, O_WRONLY|O_CREAT, 0666);
5041
5042 /* If the open failed, return the file descriptor right away. */
5043 if (fd < 0)
5044 return fd;
5045
5046 /*
5047 * OK, the open succeeded, but the file may have been changed from a
5048 * non-regular file to a regular file between the stat and the open.
5049 * We are assuming that the O_EXCL open handles the case where FILENAME
5050 * did not exist and is symlinked to an existing file between the stat
5051 * and open.
5052 */
5053
5054 /*
5055 * If we can open it and fstat the file descriptor, and neither check
5056 * revealed that it was a regular file, and the file has not been
5057 * replaced, return the file descriptor.
5058 */
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005059 if (fstat(fd, &finfo2) == 0
5060 && !S_ISREG(finfo2.st_mode)
5061 && finfo.st_dev == finfo2.st_dev
5062 && finfo.st_ino == finfo2.st_ino
5063 ) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005064 return fd;
Denys Vlasenko8d3e2252010-08-31 12:42:06 +02005065 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005066
5067 /* The file has been replaced. badness. */
5068 close(fd);
5069 errno = EEXIST;
5070 return -1;
5071}
5072
5073/*
5074 * Handle here documents. Normally we fork off a process to write the
5075 * data to a pipe. If the document is short, we can stuff the data in
5076 * the pipe without forking.
5077 */
5078/* openhere needs this forward reference */
5079static void expandhere(union node *arg, int fd);
5080static int
5081openhere(union node *redir)
5082{
5083 int pip[2];
5084 size_t len = 0;
5085
5086 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005087 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005088 if (redir->type == NHERE) {
5089 len = strlen(redir->nhere.doc->narg.text);
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005090 if (len <= PIPE_BUF) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005091 full_write(pip[1], redir->nhere.doc->narg.text, len);
5092 goto out;
5093 }
5094 }
5095 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005096 /* child */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005097 close(pip[0]);
Denis Vlasenkof8535cc2008-12-03 10:36:26 +00005098 ignoresig(SIGINT); //signal(SIGINT, SIG_IGN);
5099 ignoresig(SIGQUIT); //signal(SIGQUIT, SIG_IGN);
5100 ignoresig(SIGHUP); //signal(SIGHUP, SIG_IGN);
5101 ignoresig(SIGTSTP); //signal(SIGTSTP, SIG_IGN);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005102 signal(SIGPIPE, SIG_DFL);
5103 if (redir->type == NHERE)
5104 full_write(pip[1], redir->nhere.doc->narg.text, len);
Denis Vlasenko0b769642008-07-24 07:54:57 +00005105 else /* NXHERE */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005106 expandhere(redir->nhere.doc, pip[1]);
Bernhard Reutner-Fischer636a1f82008-05-19 09:29:47 +00005107 _exit(EXIT_SUCCESS);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005108 }
5109 out:
5110 close(pip[1]);
5111 return pip[0];
5112}
5113
5114static int
5115openredirect(union node *redir)
5116{
5117 char *fname;
5118 int f;
5119
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02005120 fname = redir->nfile.expfname;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005121 switch (redir->nfile.type) {
5122 case NFROM:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005123 f = open(fname, O_RDONLY);
5124 if (f < 0)
5125 goto eopen;
5126 break;
5127 case NFROMTO:
Andreas Bühmannda75f442010-06-24 04:32:37 +02005128 f = open(fname, O_RDWR|O_CREAT, 0666);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005129 if (f < 0)
5130 goto ecreate;
5131 break;
5132 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00005133#if ENABLE_ASH_BASH_COMPAT
5134 case NTO2:
5135#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005136 /* Take care of noclobber mode. */
5137 if (Cflag) {
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005138 f = noclobberopen(fname);
5139 if (f < 0)
5140 goto ecreate;
5141 break;
5142 }
5143 /* FALLTHROUGH */
5144 case NCLOBBER:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005145 f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
5146 if (f < 0)
5147 goto ecreate;
5148 break;
5149 case NAPPEND:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005150 f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666);
5151 if (f < 0)
5152 goto ecreate;
5153 break;
5154 default:
5155#if DEBUG
5156 abort();
5157#endif
5158 /* Fall through to eliminate warning. */
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005159/* Our single caller does this itself */
Denis Vlasenko0b769642008-07-24 07:54:57 +00005160// case NTOFD:
5161// case NFROMFD:
5162// f = -1;
5163// break;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005164 case NHERE:
5165 case NXHERE:
5166 f = openhere(redir);
5167 break;
5168 }
5169
5170 return f;
5171 ecreate:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005172 ash_msg_and_raise_error("can't create %s: %s", fname, errmsg(errno, "nonexistent directory"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005173 eopen:
Bernhard Reutner-Fischera53de7f2008-07-21 13:46:54 +00005174 ash_msg_and_raise_error("can't open %s: %s", fname, errmsg(errno, "no such file"));
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005175}
5176
5177/*
5178 * Copy a file descriptor to be >= to. Returns -1
5179 * if the source file descriptor is closed, EMPTY if there are no unused
5180 * file descriptors left.
5181 */
Denis Vlasenko5a867312008-07-24 19:46:38 +00005182/* 0x800..00: bit to set in "to" to request dup2 instead of fcntl(F_DUPFD).
5183 * old code was doing close(to) prior to copyfd() to achieve the same */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005184enum {
5185 COPYFD_EXACT = (int)~(INT_MAX),
5186 COPYFD_RESTORE = (int)((unsigned)COPYFD_EXACT >> 1),
5187};
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005188static int
5189copyfd(int from, int to)
5190{
5191 int newfd;
5192
Denis Vlasenko5a867312008-07-24 19:46:38 +00005193 if (to & COPYFD_EXACT) {
5194 to &= ~COPYFD_EXACT;
5195 /*if (from != to)*/
5196 newfd = dup2(from, to);
5197 } else {
5198 newfd = fcntl(from, F_DUPFD, to);
5199 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005200 if (newfd < 0) {
5201 if (errno == EMFILE)
5202 return EMPTY;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005203 /* Happens when source fd is not open: try "echo >&99" */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005204 ash_msg_and_raise_error("%d: %m", from);
5205 }
5206 return newfd;
5207}
5208
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005209/* Struct def and variable are moved down to the first usage site */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005210struct two_fd_t {
5211 int orig, copy;
5212};
Denis Vlasenko0b769642008-07-24 07:54:57 +00005213struct redirtab {
5214 struct redirtab *next;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005215 int nullredirs;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005216 int pair_count;
Denys Vlasenko606291b2009-09-23 23:15:43 +02005217 struct two_fd_t two_fd[];
Denis Vlasenko0b769642008-07-24 07:54:57 +00005218};
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005219#define redirlist (G_var.redirlist)
Denis Vlasenko0b769642008-07-24 07:54:57 +00005220
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005221static int need_to_remember(struct redirtab *rp, int fd)
5222{
5223 int i;
5224
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005225 if (!rp) /* remembering was not requested */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005226 return 0;
5227
5228 for (i = 0; i < rp->pair_count; i++) {
5229 if (rp->two_fd[i].orig == fd) {
5230 /* already remembered */
5231 return 0;
5232 }
5233 }
5234 return 1;
5235}
5236
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005237/* "hidden" fd is a fd used to read scripts, or a copy of such */
5238static int is_hidden_fd(struct redirtab *rp, int fd)
5239{
5240 int i;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005241 struct parsefile *pf;
5242
5243 if (fd == -1)
5244 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005245 /* Check open scripts' fds */
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005246 pf = g_parsefile;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005247 while (pf) {
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005248 /* We skip pf_fd == 0 case because of the following case:
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005249 * $ ash # running ash interactively
5250 * $ . ./script.sh
5251 * and in script.sh: "exec 9>&0".
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005252 * Even though top-level pf_fd _is_ 0,
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005253 * it's still ok to use it: "read" builtin uses it,
5254 * why should we cripple "exec" builtin?
5255 */
Denys Vlasenko79b3d422010-06-03 04:29:08 +02005256 if (pf->pf_fd > 0 && fd == pf->pf_fd) {
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005257 return 1;
5258 }
5259 pf = pf->prev;
5260 }
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005261
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005262 if (!rp)
5263 return 0;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005264 /* Check saved fds of redirects */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005265 fd |= COPYFD_RESTORE;
5266 for (i = 0; i < rp->pair_count; i++) {
5267 if (rp->two_fd[i].copy == fd) {
5268 return 1;
5269 }
5270 }
5271 return 0;
5272}
5273
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005274/*
5275 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
5276 * old file descriptors are stashed away so that the redirection can be
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005277 * undone by calling popredir.
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005278 */
5279/* flags passed to redirect */
5280#define REDIR_PUSH 01 /* save previous values of file descriptors */
5281#define REDIR_SAVEFD2 03 /* set preverrout */
5282static void
5283redirect(union node *redir, int flags)
5284{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005285 struct redirtab *sv;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005286 int sv_pos;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005287 int i;
5288 int fd;
5289 int newfd;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005290 int copied_fd2 = -1;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005291
Denis Vlasenko01631112007-12-16 17:20:38 +00005292 g_nullredirs++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005293 if (!redir) {
5294 return;
5295 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005296
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005297 sv = NULL;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005298 sv_pos = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005299 INT_OFF;
5300 if (flags & REDIR_PUSH) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005301 union node *tmp = redir;
5302 do {
5303 sv_pos++;
Denis Vlasenko559691a2008-10-05 18:39:31 +00005304#if ENABLE_ASH_BASH_COMPAT
Chris Metcalfc3c1fb62010-01-08 13:18:06 +01005305 if (tmp->nfile.type == NTO2)
Denis Vlasenko559691a2008-10-05 18:39:31 +00005306 sv_pos++;
5307#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005308 tmp = tmp->nfile.next;
5309 } while (tmp);
5310 sv = ckmalloc(sizeof(*sv) + sv_pos * sizeof(sv->two_fd[0]));
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005311 sv->next = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005312 sv->pair_count = sv_pos;
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005313 redirlist = sv;
Denis Vlasenko01631112007-12-16 17:20:38 +00005314 sv->nullredirs = g_nullredirs - 1;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005315 g_nullredirs = 0;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005316 while (sv_pos > 0) {
5317 sv_pos--;
5318 sv->two_fd[sv_pos].orig = sv->two_fd[sv_pos].copy = EMPTY;
5319 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005320 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005321
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005322 do {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005323 int right_fd = -1;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005324 fd = redir->nfile.fd;
Denis Vlasenko0b769642008-07-24 07:54:57 +00005325 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005326 right_fd = redir->ndup.dupfd;
5327 //bb_error_msg("doing %d > %d", fd, right_fd);
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005328 /* redirect from/to same file descriptor? */
5329 if (right_fd == fd)
5330 continue;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005331 /* "echo >&10" and 10 is a fd opened to a sh script? */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005332 if (is_hidden_fd(sv, right_fd)) {
5333 errno = EBADF; /* as if it is closed */
5334 ash_msg_and_raise_error("%d: %m", right_fd);
5335 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005336 newfd = -1;
5337 } else {
5338 newfd = openredirect(redir); /* always >= 0 */
5339 if (fd == newfd) {
5340 /* Descriptor wasn't open before redirect.
5341 * Mark it for close in the future */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005342 if (need_to_remember(sv, fd)) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005343 goto remember_to_close;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005344 }
Denis Vlasenko0b769642008-07-24 07:54:57 +00005345 continue;
5346 }
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005347 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005348#if ENABLE_ASH_BASH_COMPAT
5349 redirect_more:
5350#endif
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005351 if (need_to_remember(sv, fd)) {
Denis Vlasenko0b769642008-07-24 07:54:57 +00005352 /* Copy old descriptor */
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +02005353 /* Careful to not accidentally "save"
5354 * to the same fd as right side fd in N>&M */
5355 int minfd = right_fd < 10 ? 10 : right_fd + 1;
5356 i = fcntl(fd, F_DUPFD, minfd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005357/* You'd expect copy to be CLOEXECed. Currently these extra "saved" fds
5358 * are closed in popredir() in the child, preventing them from leaking
5359 * into child. (popredir() also cleans up the mess in case of failures)
5360 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005361 if (i == -1) {
5362 i = errno;
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005363 if (i != EBADF) {
5364 /* Strange error (e.g. "too many files" EMFILE?) */
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005365 if (newfd >= 0)
5366 close(newfd);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005367 errno = i;
5368 ash_msg_and_raise_error("%d: %m", fd);
5369 /* NOTREACHED */
5370 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005371 /* EBADF: it is not open - good, remember to close it */
5372 remember_to_close:
5373 i = CLOSED;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005374 } else { /* fd is open, save its copy */
5375 /* "exec fd>&-" should not close fds
5376 * which point to script file(s).
5377 * Force them to be restored afterwards */
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00005378 if (is_hidden_fd(sv, fd))
5379 i |= COPYFD_RESTORE;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005380 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005381 if (fd == 2)
5382 copied_fd2 = i;
5383 sv->two_fd[sv_pos].orig = fd;
5384 sv->two_fd[sv_pos].copy = i;
5385 sv_pos++;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005386 }
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005387 if (newfd < 0) {
5388 /* NTOFD/NFROMFD: copy redir->ndup.dupfd to fd */
Denis Vlasenko22f74142008-07-24 22:34:43 +00005389 if (redir->ndup.dupfd < 0) { /* "fd>&-" */
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005390 /* Don't want to trigger debugging */
5391 if (fd != -1)
5392 close(fd);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005393 } else {
5394 copyfd(redir->ndup.dupfd, fd | COPYFD_EXACT);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005395 }
Denis Vlasenko5a867312008-07-24 19:46:38 +00005396 } else if (fd != newfd) { /* move newfd to fd */
5397 copyfd(newfd, fd | COPYFD_EXACT);
Denis Vlasenko559691a2008-10-05 18:39:31 +00005398#if ENABLE_ASH_BASH_COMPAT
5399 if (!(redir->nfile.type == NTO2 && fd == 2))
5400#endif
5401 close(newfd);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005402 }
Denis Vlasenko559691a2008-10-05 18:39:31 +00005403#if ENABLE_ASH_BASH_COMPAT
5404 if (redir->nfile.type == NTO2 && fd == 1) {
5405 /* We already redirected it to fd 1, now copy it to 2 */
5406 newfd = 1;
5407 fd = 2;
5408 goto redirect_more;
5409 }
5410#endif
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00005411 } while ((redir = redir->nfile.next) != NULL);
Denis Vlasenko8d924ec2008-07-24 11:34:27 +00005412
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005413 INT_ON;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005414 if ((flags & REDIR_SAVEFD2) && copied_fd2 >= 0)
5415 preverrout_fd = copied_fd2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005416}
5417
5418/*
5419 * Undo the effects of the last redirection.
5420 */
5421static void
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005422popredir(int drop, int restore)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005423{
5424 struct redirtab *rp;
5425 int i;
5426
Denis Vlasenko01631112007-12-16 17:20:38 +00005427 if (--g_nullredirs >= 0)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005428 return;
5429 INT_OFF;
5430 rp = redirlist;
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005431 for (i = 0; i < rp->pair_count; i++) {
5432 int fd = rp->two_fd[i].orig;
Denis Vlasenko22f74142008-07-24 22:34:43 +00005433 int copy = rp->two_fd[i].copy;
5434 if (copy == CLOSED) {
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005435 if (!drop)
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +00005436 close(fd);
Denis Vlasenko7d75a962007-11-22 08:16:57 +00005437 continue;
5438 }
Denis Vlasenko22f74142008-07-24 22:34:43 +00005439 if (copy != EMPTY) {
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005440 if (!drop || (restore && (copy & COPYFD_RESTORE))) {
Denis Vlasenko22f74142008-07-24 22:34:43 +00005441 copy &= ~COPYFD_RESTORE;
Denis Vlasenko5a867312008-07-24 19:46:38 +00005442 /*close(fd);*/
Denis Vlasenko22f74142008-07-24 22:34:43 +00005443 copyfd(copy, fd | COPYFD_EXACT);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005444 }
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00005445 close(copy & ~COPYFD_RESTORE);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005446 }
5447 }
5448 redirlist = rp->next;
Denis Vlasenko01631112007-12-16 17:20:38 +00005449 g_nullredirs = rp->nullredirs;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005450 free(rp);
5451 INT_ON;
5452}
5453
5454/*
5455 * Undo all redirections. Called on error or interrupt.
5456 */
5457
5458/*
5459 * Discard all saved file descriptors.
5460 */
5461static void
5462clearredir(int drop)
5463{
5464 for (;;) {
Denis Vlasenko01631112007-12-16 17:20:38 +00005465 g_nullredirs = 0;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005466 if (!redirlist)
5467 break;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00005468 popredir(drop, /*restore:*/ 0);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005469 }
5470}
5471
5472static int
5473redirectsafe(union node *redir, int flags)
5474{
5475 int err;
5476 volatile int saveint;
5477 struct jmploc *volatile savehandler = exception_handler;
5478 struct jmploc jmploc;
5479
5480 SAVE_INT(saveint);
Denis Vlasenko5a867312008-07-24 19:46:38 +00005481 /* "echo 9>/dev/null; echo >&9; echo result: $?" - result should be 1, not 2! */
5482 err = setjmp(jmploc.loc); // huh?? was = setjmp(jmploc.loc) * 2;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005483 if (!err) {
5484 exception_handler = &jmploc;
5485 redirect(redir, flags);
5486 }
5487 exception_handler = savehandler;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00005488 if (err && exception_type != EXERROR)
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00005489 longjmp(exception_handler->loc, 1);
5490 RESTORE_INT(saveint);
5491 return err;
5492}
5493
5494
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005495/* ============ Routines to expand arguments to commands
5496 *
5497 * We have to deal with backquotes, shell variables, and file metacharacters.
5498 */
5499
Mike Frysinger98c52642009-04-02 10:02:37 +00005500#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005501static arith_t
5502ash_arith(const char *s)
5503{
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005504 arith_state_t math_state;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005505 arith_t result;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005506
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005507 math_state.lookupvar = lookupvar;
5508 math_state.setvar = setvar2;
5509 //math_state.endofname = endofname;
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005510
5511 INT_OFF;
Denys Vlasenko06d44d72010-09-13 12:49:03 +02005512 result = arith(&math_state, s);
Denys Vlasenko063847d2010-09-15 13:33:02 +02005513 if (math_state.errmsg)
5514 ash_msg_and_raise_error(math_state.errmsg);
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00005515 INT_ON;
5516
5517 return result;
5518}
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005519#endif
5520
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005521/*
5522 * expandarg flags
5523 */
5524#define EXP_FULL 0x1 /* perform word splitting & file globbing */
5525#define EXP_TILDE 0x2 /* do normal tilde expansion */
5526#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
5527#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
5528#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
5529#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */
5530#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
5531#define EXP_WORD 0x80 /* expand word in parameter expansion */
5532#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */
5533/*
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005534 * rmescape() flags
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005535 */
5536#define RMESCAPE_ALLOC 0x1 /* Allocate a new string */
5537#define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */
5538#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */
5539#define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */
5540#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
5541
5542/*
5543 * Structure specifying which parts of the string should be searched
5544 * for IFS characters.
5545 */
5546struct ifsregion {
5547 struct ifsregion *next; /* next region in list */
5548 int begoff; /* offset of start of region */
5549 int endoff; /* offset of end of region */
5550 int nulonly; /* search for nul bytes only */
5551};
5552
5553struct arglist {
5554 struct strlist *list;
5555 struct strlist **lastp;
5556};
5557
5558/* output of current string */
5559static char *expdest;
5560/* list of back quote expressions */
5561static struct nodelist *argbackq;
5562/* first struct in list of ifs regions */
5563static struct ifsregion ifsfirst;
5564/* last struct in list */
5565static struct ifsregion *ifslastp;
5566/* holds expanded arg list */
5567static struct arglist exparg;
5568
5569/*
5570 * Our own itoa().
5571 */
Denys Vlasenko26777aa2010-11-22 23:49:10 +01005572#if !ENABLE_SH_MATH_SUPPORT
5573/* cvtnum() is used even if math support is off (to prepare $? values and such) */
5574typedef long arith_t;
5575# define ARITH_FMT "%ld"
5576#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005577static int
5578cvtnum(arith_t num)
5579{
5580 int len;
5581
5582 expdest = makestrspace(32, expdest);
Denys Vlasenkobed7c812010-09-16 11:50:46 +02005583 len = fmtstr(expdest, 32, ARITH_FMT, num);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005584 STADJUST(len, expdest);
5585 return len;
5586}
5587
5588static size_t
5589esclen(const char *start, const char *p)
5590{
5591 size_t esc = 0;
5592
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005593 while (p > start && (unsigned char)*--p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005594 esc++;
5595 }
5596 return esc;
5597}
5598
5599/*
5600 * Remove any CTLESC characters from a string.
5601 */
5602static char *
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005603rmescapes(char *str, int flag)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005604{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00005605 static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' };
Denis Vlasenkof20de5b2007-04-29 23:42:54 +00005606
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005607 char *p, *q, *r;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005608 unsigned inquotes;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005609 unsigned protect_against_glob;
5610 unsigned globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005611
5612 p = strpbrk(str, qchars);
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005613 if (!p)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005614 return str;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005615
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005616 q = p;
5617 r = str;
5618 if (flag & RMESCAPE_ALLOC) {
5619 size_t len = p - str;
5620 size_t fulllen = len + strlen(p) + 1;
5621
5622 if (flag & RMESCAPE_GROW) {
Colin Watson3963d942010-04-26 14:21:27 +02005623 int strloc = str - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005624 r = makestrspace(fulllen, expdest);
Colin Watson3963d942010-04-26 14:21:27 +02005625 /* p and str may be invalidated by makestrspace */
5626 str = (char *)stackblock() + strloc;
5627 p = str + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005628 } else if (flag & RMESCAPE_HEAP) {
5629 r = ckmalloc(fulllen);
5630 } else {
5631 r = stalloc(fulllen);
5632 }
5633 q = r;
5634 if (len > 0) {
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005635 q = (char *)memcpy(q, str, len) + len;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005636 }
5637 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005638
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005639 inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED;
5640 globbing = flag & RMESCAPE_GLOB;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005641 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005642 while (*p) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005643 if ((unsigned char)*p == CTLQUOTEMARK) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005644// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0
5645// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok?
5646// Note: both inquotes and protect_against_glob only affect whether
5647// CTLESC,<ch> gets converted to <ch> or to \<ch>
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005648 inquotes = ~inquotes;
5649 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005650 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005651 continue;
5652 }
5653 if (*p == '\\') {
5654 /* naked back slash */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005655 protect_against_glob = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005656 goto copy;
5657 }
Denys Vlasenkocd716832009-11-28 22:14:02 +01005658 if ((unsigned char)*p == CTLESC) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005659 p++;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005660 if (protect_against_glob && inquotes && *p != '/') {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005661 *q++ = '\\';
5662 }
5663 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005664 protect_against_glob = globbing;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005665 copy:
5666 *q++ = *p++;
5667 }
5668 *q = '\0';
5669 if (flag & RMESCAPE_GROW) {
5670 expdest = r;
5671 STADJUST(q - r + 1, expdest);
5672 }
5673 return r;
5674}
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005675#define pmatch(a, b) !fnmatch((a), (b), 0)
5676
5677/*
5678 * Prepare a pattern for a expmeta (internal glob(3)) call.
5679 *
5680 * Returns an stalloced string.
5681 */
5682static char *
5683preglob(const char *pattern, int quoted, int flag)
5684{
5685 flag |= RMESCAPE_GLOB;
5686 if (quoted) {
5687 flag |= RMESCAPE_QUOTED;
5688 }
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005689 return rmescapes((char *)pattern, flag);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005690}
5691
5692/*
5693 * Put a string on the stack.
5694 */
5695static void
5696memtodest(const char *p, size_t len, int syntax, int quotes)
5697{
5698 char *q = expdest;
5699
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005700 q = makestrspace(quotes ? len * 2 : len, q);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005701
5702 while (len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01005703 unsigned char c = *p++;
5704 if (c == '\0')
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005705 continue;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02005706 if (quotes) {
5707 int n = SIT(c, syntax);
5708 if (n == CCTL || n == CBACK)
5709 USTPUTC(CTLESC, q);
5710 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005711 USTPUTC(c, q);
5712 }
5713
5714 expdest = q;
5715}
5716
5717static void
5718strtodest(const char *p, int syntax, int quotes)
5719{
5720 memtodest(p, strlen(p), syntax, quotes);
5721}
5722
5723/*
5724 * Record the fact that we have to scan this region of the
5725 * string for IFS characters.
5726 */
5727static void
5728recordregion(int start, int end, int nulonly)
5729{
5730 struct ifsregion *ifsp;
5731
5732 if (ifslastp == NULL) {
5733 ifsp = &ifsfirst;
5734 } else {
5735 INT_OFF;
Denis Vlasenko597906c2008-02-20 16:38:54 +00005736 ifsp = ckzalloc(sizeof(*ifsp));
5737 /*ifsp->next = NULL; - ckzalloc did it */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005738 ifslastp->next = ifsp;
5739 INT_ON;
5740 }
5741 ifslastp = ifsp;
5742 ifslastp->begoff = start;
5743 ifslastp->endoff = end;
5744 ifslastp->nulonly = nulonly;
5745}
5746
5747static void
5748removerecordregions(int endoff)
5749{
5750 if (ifslastp == NULL)
5751 return;
5752
5753 if (ifsfirst.endoff > endoff) {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005754 while (ifsfirst.next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005755 struct ifsregion *ifsp;
5756 INT_OFF;
5757 ifsp = ifsfirst.next->next;
5758 free(ifsfirst.next);
5759 ifsfirst.next = ifsp;
5760 INT_ON;
5761 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005762 if (ifsfirst.begoff > endoff) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005763 ifslastp = NULL;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005764 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005765 ifslastp = &ifsfirst;
5766 ifsfirst.endoff = endoff;
5767 }
5768 return;
5769 }
5770
5771 ifslastp = &ifsfirst;
5772 while (ifslastp->next && ifslastp->next->begoff < endoff)
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005773 ifslastp = ifslastp->next;
5774 while (ifslastp->next) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005775 struct ifsregion *ifsp;
5776 INT_OFF;
5777 ifsp = ifslastp->next->next;
5778 free(ifslastp->next);
5779 ifslastp->next = ifsp;
5780 INT_ON;
5781 }
5782 if (ifslastp->endoff > endoff)
5783 ifslastp->endoff = endoff;
5784}
5785
5786static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005787exptilde(char *startp, char *p, int flags)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005788{
Denys Vlasenkocd716832009-11-28 22:14:02 +01005789 unsigned char c;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005790 char *name;
5791 struct passwd *pw;
5792 const char *home;
Denys Vlasenko1166d7b2009-09-16 16:20:31 +02005793 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005794 int startloc;
5795
5796 name = p + 1;
5797
5798 while ((c = *++p) != '\0') {
5799 switch (c) {
5800 case CTLESC:
5801 return startp;
5802 case CTLQUOTEMARK:
5803 return startp;
5804 case ':':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02005805 if (flags & EXP_VARTILDE)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005806 goto done;
5807 break;
5808 case '/':
5809 case CTLENDVAR:
5810 goto done;
5811 }
5812 }
5813 done:
5814 *p = '\0';
5815 if (*name == '\0') {
Denys Vlasenkoea8b2522010-06-02 12:57:26 +02005816 home = lookupvar("HOME");
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005817 } else {
5818 pw = getpwnam(name);
5819 if (pw == NULL)
5820 goto lose;
5821 home = pw->pw_dir;
5822 }
5823 if (!home || !*home)
5824 goto lose;
5825 *p = c;
5826 startloc = expdest - (char *)stackblock();
5827 strtodest(home, SQSYNTAX, quotes);
5828 recordregion(startloc, expdest - (char *)stackblock(), 0);
5829 return p;
5830 lose:
5831 *p = c;
5832 return startp;
5833}
5834
5835/*
5836 * Execute a command inside back quotes. If it's a builtin command, we
5837 * want to save its output in a block obtained from malloc. Otherwise
5838 * we fork off a subprocess and get the output of the command via a pipe.
5839 * Should be called with interrupts off.
5840 */
5841struct backcmd { /* result of evalbackcmd */
5842 int fd; /* file descriptor to read from */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005843 int nleft; /* number of chars in buffer */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00005844 char *buf; /* buffer */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005845 struct job *jp; /* job structure for command */
5846};
5847
5848/* These forward decls are needed to use "eval" code for backticks handling: */
Denis Vlasenko448d30e2008-06-27 00:24:11 +00005849static uint8_t back_exitstatus; /* exit status of backquoted command */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005850#define EV_EXIT 01 /* exit after evaluating tree */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02005851static void evaltree(union node *, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005852
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02005853static void FAST_FUNC
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005854evalbackcmd(union node *n, struct backcmd *result)
5855{
5856 int saveherefd;
5857
5858 result->fd = -1;
5859 result->buf = NULL;
5860 result->nleft = 0;
5861 result->jp = NULL;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005862 if (n == NULL)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005863 goto out;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005864
5865 saveherefd = herefd;
5866 herefd = -1;
5867
5868 {
5869 int pip[2];
5870 struct job *jp;
5871
5872 if (pipe(pip) < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00005873 ash_msg_and_raise_error("pipe call failed");
Denis Vlasenko68404f12008-03-17 09:00:54 +00005874 jp = makejob(/*n,*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005875 if (forkshell(jp, n, FORK_NOJOB) == 0) {
5876 FORCE_INT_ON;
5877 close(pip[0]);
5878 if (pip[1] != 1) {
Denis Vlasenko5a867312008-07-24 19:46:38 +00005879 /*close(1);*/
5880 copyfd(pip[1], 1 | COPYFD_EXACT);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005881 close(pip[1]);
5882 }
5883 eflag = 0;
5884 evaltree(n, EV_EXIT); /* actually evaltreenr... */
5885 /* NOTREACHED */
5886 }
5887 close(pip[1]);
5888 result->fd = pip[0];
5889 result->jp = jp;
5890 }
5891 herefd = saveherefd;
5892 out:
5893 TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n",
5894 result->fd, result->buf, result->nleft, result->jp));
5895}
5896
5897/*
5898 * Expand stuff in backwards quotes.
5899 */
5900static void
5901expbackq(union node *cmd, int quoted, int quotes)
5902{
5903 struct backcmd in;
5904 int i;
5905 char buf[128];
5906 char *p;
5907 char *dest;
5908 int startloc;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00005909 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005910 struct stackmark smark;
5911
5912 INT_OFF;
5913 setstackmark(&smark);
5914 dest = expdest;
5915 startloc = dest - (char *)stackblock();
5916 grabstackstr(dest);
5917 evalbackcmd(cmd, &in);
5918 popstackmark(&smark);
5919
5920 p = in.buf;
5921 i = in.nleft;
5922 if (i == 0)
5923 goto read;
5924 for (;;) {
5925 memtodest(p, i, syntax, quotes);
5926 read:
5927 if (in.fd < 0)
5928 break;
Denys Vlasenko80542ba2011-05-08 21:23:43 +02005929 i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005930 TRACE(("expbackq: read returns %d\n", i));
5931 if (i <= 0)
5932 break;
5933 p = buf;
5934 }
5935
Denis Vlasenko60818682007-09-28 22:07:23 +00005936 free(in.buf);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005937 if (in.fd >= 0) {
5938 close(in.fd);
5939 back_exitstatus = waitforjob(in.jp);
5940 }
5941 INT_ON;
5942
5943 /* Eat all trailing newlines */
5944 dest = expdest;
5945 for (; dest > (char *)stackblock() && dest[-1] == '\n';)
5946 STUNPUTC(dest);
5947 expdest = dest;
5948
5949 if (quoted == 0)
5950 recordregion(startloc, dest - (char *)stackblock(), 0);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02005951 TRACE(("evalbackq: size:%d:'%.*s'\n",
5952 (int)((dest - (char *)stackblock()) - startloc),
5953 (int)((dest - (char *)stackblock()) - startloc),
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005954 stackblock() + startloc));
5955}
5956
Mike Frysinger98c52642009-04-02 10:02:37 +00005957#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005958/*
5959 * Expand arithmetic expression. Backup to start of expression,
5960 * evaluate, place result in (backed up) result, adjust string position.
5961 */
5962static void
5963expari(int quotes)
5964{
5965 char *p, *start;
5966 int begoff;
5967 int flag;
5968 int len;
5969
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00005970 /* ifsfree(); */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005971
5972 /*
5973 * This routine is slightly over-complicated for
5974 * efficiency. Next we scan backwards looking for the
5975 * start of arithmetic.
5976 */
5977 start = stackblock();
5978 p = expdest - 1;
5979 *p = '\0';
5980 p--;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005981 while (1) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005982 int esc;
5983
Denys Vlasenkocd716832009-11-28 22:14:02 +01005984 while ((unsigned char)*p != CTLARI) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00005985 p--;
5986#if DEBUG
5987 if (p < start) {
5988 ash_msg_and_raise_error("missing CTLARI (shouldn't happen)");
5989 }
5990#endif
5991 }
5992
5993 esc = esclen(start, p);
5994 if (!(esc % 2)) {
5995 break;
5996 }
5997
5998 p -= esc + 1;
Denys Vlasenko940c7202011-03-02 04:07:14 +01005999 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006000
6001 begoff = p - start;
6002
6003 removerecordregions(begoff);
6004
6005 flag = p[1];
6006
6007 expdest = p;
6008
6009 if (quotes)
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006010 rmescapes(p + 2, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006011
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +00006012 len = cvtnum(ash_arith(p + 2));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006013
6014 if (flag != '"')
6015 recordregion(begoff, begoff + len, 0);
6016}
6017#endif
6018
6019/* argstr needs it */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006020static char *evalvar(char *p, int flags, struct strlist *var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006021
6022/*
6023 * Perform variable and command substitution. If EXP_FULL is set, output CTLESC
6024 * characters to allow for further processing. Otherwise treat
6025 * $@ like $* since no splitting will be performed.
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006026 *
6027 * var_str_list (can be NULL) is a list of "VAR=val" strings which take precedence
6028 * over shell varables. Needed for "A=a B=$A; echo $B" case - we use it
6029 * for correct expansion of "B=$A" word.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006030 */
6031static void
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006032argstr(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006033{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00006034 static const char spclchars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006035 '=',
6036 ':',
6037 CTLQUOTEMARK,
6038 CTLENDVAR,
6039 CTLESC,
6040 CTLVAR,
6041 CTLBACKQ,
6042 CTLBACKQ | CTLQUOTE,
Mike Frysinger98c52642009-04-02 10:02:37 +00006043#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006044 CTLENDARI,
6045#endif
Denys Vlasenkocd716832009-11-28 22:14:02 +01006046 '\0'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006047 };
6048 const char *reject = spclchars;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006049 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
6050 int breakall = flags & EXP_WORD;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006051 int inquotes;
6052 size_t length;
6053 int startloc;
6054
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006055 if (!(flags & EXP_VARTILDE)) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006056 reject += 2;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006057 } else if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006058 reject++;
6059 }
6060 inquotes = 0;
6061 length = 0;
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006062 if (flags & EXP_TILDE) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006063 char *q;
6064
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006065 flags &= ~EXP_TILDE;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006066 tilde:
6067 q = p;
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006068 if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006069 q++;
6070 if (*q == '~')
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006071 p = exptilde(p, q, flags);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006072 }
6073 start:
6074 startloc = expdest - (char *)stackblock();
6075 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006076 unsigned char c;
6077
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006078 length += strcspn(p + length, reject);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006079 c = p[length];
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006080 if (c) {
6081 if (!(c & 0x80)
Denys Vlasenko958581a2010-09-12 15:04:27 +02006082 IF_SH_MATH_SUPPORT(|| c == CTLENDARI)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006083 ) {
6084 /* c == '=' || c == ':' || c == CTLENDARI */
6085 length++;
6086 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006087 }
6088 if (length > 0) {
6089 int newloc;
6090 expdest = stack_nputstr(p, length, expdest);
6091 newloc = expdest - (char *)stackblock();
6092 if (breakall && !inquotes && newloc > startloc) {
6093 recordregion(startloc, newloc, 0);
6094 }
6095 startloc = newloc;
6096 }
6097 p += length + 1;
6098 length = 0;
6099
6100 switch (c) {
6101 case '\0':
6102 goto breakloop;
6103 case '=':
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006104 if (flags & EXP_VARTILDE2) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006105 p--;
6106 continue;
6107 }
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006108 flags |= EXP_VARTILDE2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006109 reject++;
6110 /* fall through */
6111 case ':':
6112 /*
6113 * sort of a hack - expand tildes in variable
6114 * assignments (after the first '=' and after ':'s).
6115 */
6116 if (*--p == '~') {
6117 goto tilde;
6118 }
6119 continue;
6120 }
6121
6122 switch (c) {
6123 case CTLENDVAR: /* ??? */
6124 goto breakloop;
6125 case CTLQUOTEMARK:
6126 /* "$@" syntax adherence hack */
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006127 if (!inquotes
6128 && memcmp(p, dolatstr, 4) == 0
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006129 && ( p[4] == (char)CTLQUOTEMARK
6130 || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK)
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006131 )
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006132 ) {
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006133 p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006134 goto start;
6135 }
6136 inquotes = !inquotes;
6137 addquote:
6138 if (quotes) {
6139 p--;
6140 length++;
6141 startloc++;
6142 }
6143 break;
6144 case CTLESC:
6145 startloc++;
6146 length++;
6147 goto addquote;
6148 case CTLVAR:
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006149 TRACE(("argstr: evalvar('%s')\n", p));
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006150 p = evalvar(p, flags, var_str_list);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006151 TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock()));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006152 goto start;
6153 case CTLBACKQ:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006154 c = '\0';
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006155 case CTLBACKQ|CTLQUOTE:
6156 expbackq(argbackq->n, c, quotes);
6157 argbackq = argbackq->next;
6158 goto start;
Mike Frysinger98c52642009-04-02 10:02:37 +00006159#if ENABLE_SH_MATH_SUPPORT
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006160 case CTLENDARI:
6161 p--;
6162 expari(quotes);
6163 goto start;
6164#endif
6165 }
6166 }
Denys Vlasenko958581a2010-09-12 15:04:27 +02006167 breakloop: ;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006168}
6169
6170static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006171scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM,
6172 char *pattern, int quotes, int zero)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006173{
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006174 char *loc, *loc2;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006175 char c;
6176
6177 loc = startp;
6178 loc2 = rmesc;
6179 do {
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006180 int match;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006181 const char *s = loc2;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006182
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006183 c = *loc2;
6184 if (zero) {
6185 *loc2 = '\0';
6186 s = rmesc;
6187 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006188 match = pmatch(pattern, s);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006189
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006190 *loc2 = c;
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006191 if (match)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006192 return loc;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006193 if (quotes && (unsigned char)*loc == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006194 loc++;
6195 loc++;
6196 loc2++;
6197 } while (c);
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006198 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006199}
6200
6201static char *
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006202scanright(char *startp, char *rmesc, char *rmescend,
6203 char *pattern, int quotes, int match_at_start)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006204{
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006205#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6206 int try2optimize = match_at_start;
6207#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006208 int esc = 0;
6209 char *loc;
6210 char *loc2;
6211
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006212 /* If we called by "${v/pattern/repl}" or "${v//pattern/repl}":
6213 * startp="escaped_value_of_v" rmesc="raw_value_of_v"
6214 * rmescend=""(ptr to NUL in rmesc) pattern="pattern" quotes=match_at_start=1
6215 * Logic:
6216 * loc starts at NUL at the end of startp, loc2 starts at the end of rmesc,
6217 * and on each iteration they go back two/one char until they reach the beginning.
6218 * We try to find a match in "raw_value_of_v", "raw_value_of_", "raw_value_of" etc.
6219 */
6220 /* TODO: document in what other circumstances we are called. */
6221
6222 for (loc = pattern - 1, loc2 = rmescend; loc >= startp; loc2--) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006223 int match;
6224 char c = *loc2;
6225 const char *s = loc2;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006226 if (match_at_start) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006227 *loc2 = '\0';
6228 s = rmesc;
6229 }
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006230 match = pmatch(pattern, s);
6231 //bb_error_msg("pmatch(pattern:'%s',s:'%s'):%d", pattern, s, match);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006232 *loc2 = c;
6233 if (match)
6234 return loc;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006235#if !ENABLE_ASH_OPTIMIZE_FOR_SIZE
6236 if (try2optimize) {
6237 /* Maybe we can optimize this:
6238 * if pattern ends with unescaped *, we can avoid checking
6239 * shorter strings: if "foo*" doesnt match "raw_value_of_v",
6240 * it wont match truncated "raw_value_of_" strings too.
6241 */
6242 unsigned plen = strlen(pattern);
6243 /* Does it end with "*"? */
6244 if (plen != 0 && pattern[--plen] == '*') {
6245 /* "xxxx*" is not escaped */
6246 /* "xxx\*" is escaped */
6247 /* "xx\\*" is not escaped */
6248 /* "x\\\*" is escaped */
6249 int slashes = 0;
6250 while (plen != 0 && pattern[--plen] == '\\')
6251 slashes++;
6252 if (!(slashes & 1))
6253 break; /* ends with unescaped "*" */
6254 }
6255 try2optimize = 0;
6256 }
6257#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006258 loc--;
6259 if (quotes) {
6260 if (--esc < 0) {
6261 esc = esclen(startp, loc);
6262 }
6263 if (esc % 2) {
6264 esc--;
6265 loc--;
6266 }
6267 }
6268 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006269 return NULL;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006270}
6271
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00006272static void varunset(const char *, const char *, const char *, int) NORETURN;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006273static void
6274varunset(const char *end, const char *var, const char *umsg, int varflags)
6275{
6276 const char *msg;
6277 const char *tail;
6278
6279 tail = nullstr;
6280 msg = "parameter not set";
6281 if (umsg) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006282 if ((unsigned char)*end == CTLENDVAR) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006283 if (varflags & VSNUL)
6284 tail = " or null";
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006285 } else {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006286 msg = umsg;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006287 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006288 }
Denys Vlasenko09dd6ec2010-08-07 02:44:33 +02006289 ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006290}
6291
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006292#if ENABLE_ASH_BASH_COMPAT
6293static char *
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006294parse_sub_pattern(char *arg, int varflags)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006295{
6296 char *idx, *repl = NULL;
6297 unsigned char c;
6298
Denys Vlasenko16149002010-08-06 22:06:21 +02006299 //char *org_arg = arg;
Denys Vlasenko33bbb272010-08-07 22:24:36 +02006300 //bb_error_msg("arg:'%s' varflags:%x", arg, varflags);
Denis Vlasenko2659c632008-06-14 06:04:59 +00006301 idx = arg;
6302 while (1) {
6303 c = *arg;
6304 if (!c)
6305 break;
6306 if (c == '/') {
6307 /* Only the first '/' seen is our separator */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006308 if (!repl) {
Denis Vlasenko2659c632008-06-14 06:04:59 +00006309 repl = idx + 1;
6310 c = '\0';
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006311 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006312 }
Denis Vlasenko2659c632008-06-14 06:04:59 +00006313 *idx++ = c;
Denis Vlasenko2659c632008-06-14 06:04:59 +00006314 arg++;
Denys Vlasenko33bbb272010-08-07 22:24:36 +02006315 /*
6316 * Example: v='ab\c'; echo ${v/\\b/_\\_\z_}
6317 * The result is a_\_z_c (not a\_\_z_c)!
6318 *
6319 * Enable debug prints in this function and you'll see:
6320 * ash: arg:'\\b/_\\_z_' varflags:d
6321 * ash: pattern:'\\b' repl:'_\_z_'
6322 * That is, \\b is interpreted as \\b, but \\_ as \_!
6323 * IOW: search pattern and replace string treat backslashes
6324 * differently! That is the reason why we check repl below:
6325 */
6326 if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE))
6327 arg++; /* skip both '\', not just first one */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006328 }
Denis Vlasenko29038c02008-06-14 06:14:02 +00006329 *idx = c; /* NUL */
Denys Vlasenko16149002010-08-06 22:06:21 +02006330 //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006331
6332 return repl;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006333}
6334#endif /* ENABLE_ASH_BASH_COMPAT */
6335
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006336static const char *
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006337subevalvar(char *p, char *varname, int strloc, int subtype,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006338 int startloc, int varflags, int quotes, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006339{
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006340 struct nodelist *saveargbackq = argbackq;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006341 char *startp;
6342 char *loc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006343 char *rmesc, *rmescend;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006344 char *str;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006345 IF_ASH_BASH_COMPAT(const char *repl = NULL;)
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006346 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006347 int saveherefd = herefd;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006348 int amount, resetloc;
6349 IF_ASH_BASH_COMPAT(int workloc;)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006350 int zero;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006351 char *(*scan)(char*, char*, char*, char*, int, int);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006352
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006353 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)",
6354 // p, varname, strloc, subtype, startloc, varflags, quotes);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006355
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006356 herefd = -1;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006357 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6358 var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006359 STPUTC('\0', expdest);
6360 herefd = saveherefd;
6361 argbackq = saveargbackq;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006362 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006363
6364 switch (subtype) {
6365 case VSASSIGN:
Bernhard Reutner-Fischer200c1c42013-11-08 14:12:13 +01006366 setvar2(varname, startp);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006367 amount = startp - expdest;
6368 STADJUST(amount, expdest);
6369 return startp;
6370
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006371 case VSQUESTION:
6372 varunset(p, varname, startp, varflags);
6373 /* NOTREACHED */
6374
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006375#if ENABLE_ASH_BASH_COMPAT
6376 case VSSUBSTR:
6377 loc = str = stackblock() + strloc;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006378 /* Read POS in ${var:POS:LEN} */
6379 pos = atoi(loc); /* number(loc) errors out on "1:4" */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006380 len = str - startp - 1;
6381
6382 /* *loc != '\0', guaranteed by parser */
6383 if (quotes) {
6384 char *ptr;
6385
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006386 /* Adjust the length by the number of escapes */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006387 for (ptr = startp; ptr < (str - 1); ptr++) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006388 if ((unsigned char)*ptr == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006389 len--;
6390 ptr++;
6391 }
6392 }
6393 }
6394 orig_len = len;
6395
6396 if (*loc++ == ':') {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006397 /* ${var::LEN} */
6398 len = number(loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006399 } else {
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006400 /* Skip POS in ${var:POS:LEN} */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006401 len = orig_len;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006402 while (*loc && *loc != ':') {
6403 /* TODO?
6404 * bash complains on: var=qwe; echo ${var:1a:123}
6405 if (!isdigit(*loc))
6406 ash_msg_and_raise_error(msg_illnum, str);
6407 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006408 loc++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006409 }
6410 if (*loc++ == ':') {
6411 len = number(loc);
6412 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006413 }
Denys Vlasenko08a5dab2014-11-17 20:27:18 +01006414 if (pos < 0) {
6415 /* ${VAR:$((-n)):l} starts n chars from the end */
6416 pos = orig_len + pos;
6417 }
6418 if ((unsigned)pos >= orig_len) {
6419 /* apart from obvious ${VAR:999999:l},
6420 * covers ${VAR:$((-9999999)):l} - result is ""
6421 * (bash-compat)
6422 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006423 pos = 0;
6424 len = 0;
6425 }
6426 if (len > (orig_len - pos))
6427 len = orig_len - pos;
6428
6429 for (str = startp; pos; str++, pos--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006430 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006431 str++;
6432 }
6433 for (loc = startp; len; len--) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006434 if (quotes && (unsigned char)*str == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006435 *loc++ = *str++;
6436 *loc++ = *str++;
6437 }
6438 *loc = '\0';
6439 amount = loc - expdest;
6440 STADJUST(amount, expdest);
6441 return loc;
6442#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006443 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006444
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006445 resetloc = expdest - (char *)stackblock();
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006446
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006447 /* We'll comeback here if we grow the stack while handling
6448 * a VSREPLACE or VSREPLACEALL, since our pointers into the
6449 * stack will need rebasing, and we'll need to remove our work
6450 * areas each time
6451 */
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00006452 IF_ASH_BASH_COMPAT(restart:)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006453
6454 amount = expdest - ((char *)stackblock() + resetloc);
6455 STADJUST(-amount, expdest);
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006456 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006457
6458 rmesc = startp;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006459 rmescend = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006460 if (quotes) {
Denys Vlasenkob6c84342009-08-29 20:23:20 +02006461 rmesc = rmescapes(startp, RMESCAPE_ALLOC | RMESCAPE_GROW);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006462 if (rmesc != startp) {
6463 rmescend = expdest;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006464 startp = (char *)stackblock() + startloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006465 }
6466 }
6467 rmescend--;
Denis Vlasenko29eb3592008-05-18 14:06:08 +00006468 str = (char *)stackblock() + strloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006469 preglob(str, varflags & VSQUOTE, 0);
6470
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006471#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02006472 workloc = expdest - (char *)stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006473 if (subtype == VSREPLACE || subtype == VSREPLACEALL) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006474 char *idx, *end;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006475
Denis Vlasenkod6855d12008-09-27 14:03:25 +00006476 if (!repl) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006477 repl = parse_sub_pattern(str, varflags);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006478 //bb_error_msg("repl:'%s'", repl);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006479 if (!repl)
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006480 repl = nullstr;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006481 }
6482
6483 /* If there's no pattern to match, return the expansion unmolested */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006484 if (str[0] == '\0')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006485 return NULL;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006486
6487 len = 0;
6488 idx = startp;
6489 end = str - 1;
6490 while (idx < end) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006491 try_to_match:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006492 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006493 //bb_error_msg("scanright('%s'):'%s'", str, loc);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006494 if (!loc) {
6495 /* No match, advance */
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006496 char *restart_detect = stackblock();
6497 skip_matching:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006498 STPUTC(*idx, expdest);
Denys Vlasenkocd716832009-11-28 22:14:02 +01006499 if (quotes && (unsigned char)*idx == CTLESC) {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006500 idx++;
6501 len++;
6502 STPUTC(*idx, expdest);
6503 }
6504 if (stackblock() != restart_detect)
6505 goto restart;
6506 idx++;
6507 len++;
6508 rmesc++;
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006509 /* continue; - prone to quadratic behavior, smarter code: */
6510 if (idx >= end)
6511 break;
6512 if (str[0] == '*') {
6513 /* Pattern is "*foo". If "*foo" does not match "long_string",
6514 * it would never match "ong_string" etc, no point in trying.
6515 */
6516 goto skip_matching;
6517 }
6518 goto try_to_match;
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006519 }
6520
6521 if (subtype == VSREPLACEALL) {
6522 while (idx < loc) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006523 if (quotes && (unsigned char)*idx == CTLESC)
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006524 idx++;
6525 idx++;
6526 rmesc++;
6527 }
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006528 } else {
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006529 idx = loc;
Denis Vlasenko81c3a1d2008-12-03 11:59:12 +00006530 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006531
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006532 //bb_error_msg("repl:'%s'", repl);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006533 for (loc = (char*)repl; *loc; loc++) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006534 char *restart_detect = stackblock();
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006535 if (quotes && *loc == '\\') {
6536 STPUTC(CTLESC, expdest);
6537 len++;
6538 }
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006539 STPUTC(*loc, expdest);
6540 if (stackblock() != restart_detect)
6541 goto restart;
6542 len++;
6543 }
6544
6545 if (subtype == VSREPLACE) {
Denys Vlasenkof02c82f2010-08-06 19:14:47 +02006546 //bb_error_msg("tail:'%s', quotes:%x", idx, quotes);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006547 while (*idx) {
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006548 char *restart_detect = stackblock();
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006549 STPUTC(*idx, expdest);
6550 if (stackblock() != restart_detect)
6551 goto restart;
6552 len++;
6553 idx++;
6554 }
6555 break;
6556 }
6557 }
6558
6559 /* We've put the replaced text into a buffer at workloc, now
6560 * move it to the right place and adjust the stack.
6561 */
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006562 STPUTC('\0', expdest);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006563 startp = (char *)stackblock() + startloc;
6564 memmove(startp, (char *)stackblock() + workloc, len + 1);
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006565 //bb_error_msg("startp:'%s'", startp);
Denys Vlasenkofd33e172010-06-26 22:55:44 +02006566 amount = expdest - (startp + len);
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006567 STADJUST(-amount, expdest);
6568 return startp;
6569 }
6570#endif /* ENABLE_ASH_BASH_COMPAT */
6571
6572 subtype -= VSTRIMRIGHT;
6573#if DEBUG
6574 if (subtype < 0 || subtype > 7)
6575 abort();
6576#endif
Denys Vlasenkob76356b2010-03-13 16:19:04 +01006577 /* zero = (subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006578 zero = subtype >> 1;
6579 /* VSTRIMLEFT/VSTRIMRIGHTMAX -> scanleft */
6580 scan = (subtype & 1) ^ zero ? scanleft : scanright;
6581
6582 loc = scan(startp, rmesc, rmescend, str, quotes, zero);
6583 if (loc) {
6584 if (zero) {
6585 memmove(startp, loc, str - loc);
6586 loc = startp + (str - loc) - 1;
6587 }
6588 *loc = '\0';
6589 amount = loc - expdest;
6590 STADJUST(amount, expdest);
6591 }
6592 return loc;
6593}
6594
6595/*
6596 * Add the value of a specialized variable to the stack string.
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006597 * name parameter (examples):
6598 * ash -c 'echo $1' name:'1='
6599 * ash -c 'echo $qwe' name:'qwe='
6600 * ash -c 'echo $$' name:'$='
6601 * ash -c 'echo ${$}' name:'$='
6602 * ash -c 'echo ${$##q}' name:'$=q'
6603 * ash -c 'echo ${#$}' name:'$='
6604 * note: examples with bad shell syntax:
6605 * ash -c 'echo ${#$1}' name:'$=1'
6606 * ash -c 'echo ${#1#}' name:'1=#'
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006607 */
Denys Vlasenkoadf922e2009-10-08 14:35:37 +02006608static NOINLINE ssize_t
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006609varvalue(char *name, int varflags, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006610{
Mike Frysinger98c52642009-04-02 10:02:37 +00006611 const char *p;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006612 int num;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006613 int i;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006614 int sepq = 0;
6615 ssize_t len = 0;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006616 int subtype = varflags & VSTYPE;
Denys Vlasenko1166d7b2009-09-16 16:20:31 +02006617 int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR);
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006618 int quoted = varflags & VSQUOTE;
6619 int syntax = quoted ? DQSYNTAX : BASESYNTAX;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006620
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006621 switch (*name) {
6622 case '$':
6623 num = rootpid;
6624 goto numvar;
6625 case '?':
6626 num = exitstatus;
6627 goto numvar;
6628 case '#':
6629 num = shellparam.nparam;
6630 goto numvar;
6631 case '!':
6632 num = backgndpid;
6633 if (num == 0)
6634 return -1;
6635 numvar:
6636 len = cvtnum(num);
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006637 goto check_1char_name;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006638 case '-':
Mike Frysinger98c52642009-04-02 10:02:37 +00006639 expdest = makestrspace(NOPTS, expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006640 for (i = NOPTS - 1; i >= 0; i--) {
6641 if (optlist[i]) {
Mike Frysinger98c52642009-04-02 10:02:37 +00006642 USTPUTC(optletters(i), expdest);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006643 len++;
6644 }
6645 }
Denys Vlasenko4d8873f2009-10-04 03:14:41 +02006646 check_1char_name:
6647#if 0
6648 /* handles cases similar to ${#$1} */
6649 if (name[2] != '\0')
6650 raise_error_syntax("bad substitution");
6651#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006652 break;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006653 case '@': {
6654 char **ap;
6655 int sep;
6656
6657 if (quoted && (flags & EXP_FULL)) {
6658 /* note: this is not meant as PEOF value */
6659 sep = 1 << CHAR_BIT;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006660 goto param;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006661 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006662 /* fall through */
6663 case '*':
Denys Vlasenkocd716832009-11-28 22:14:02 +01006664 sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' ';
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006665 i = SIT(sep, syntax);
6666 if (quotes && (i == CCTL || i == CBACK))
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006667 sepq = 1;
6668 param:
6669 ap = shellparam.p;
6670 if (!ap)
6671 return -1;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02006672 while ((p = *ap++) != NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006673 size_t partlen;
6674
6675 partlen = strlen(p);
6676 len += partlen;
6677
6678 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6679 memtodest(p, partlen, syntax, quotes);
6680
6681 if (*ap && sep) {
6682 char *q;
6683
6684 len++;
6685 if (subtype == VSPLUS || subtype == VSLENGTH) {
6686 continue;
6687 }
6688 q = expdest;
6689 if (sepq)
6690 STPUTC(CTLESC, q);
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006691 /* note: may put NUL despite sep != 0
6692 * (see sep = 1 << CHAR_BIT above) */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006693 STPUTC(sep, q);
6694 expdest = q;
6695 }
6696 }
6697 return len;
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006698 } /* case '@' and '*' */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006699 case '0':
6700 case '1':
6701 case '2':
6702 case '3':
6703 case '4':
6704 case '5':
6705 case '6':
6706 case '7':
6707 case '8':
6708 case '9':
Denys Vlasenkoa00329c2009-08-30 20:05:10 +02006709 num = atoi(name); /* number(name) fails on ${N#str} etc */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006710 if (num < 0 || num > shellparam.nparam)
6711 return -1;
6712 p = num ? shellparam.p[num - 1] : arg0;
6713 goto value;
6714 default:
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006715 /* NB: name has form "VAR=..." */
6716
6717 /* "A=a B=$A" case: var_str_list is a list of "A=a" strings
6718 * which should be considered before we check variables. */
6719 if (var_str_list) {
6720 unsigned name_len = (strchrnul(name, '=') - name) + 1;
6721 p = NULL;
6722 do {
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00006723 char *str, *eq;
6724 str = var_str_list->text;
6725 eq = strchr(str, '=');
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006726 if (!eq) /* stop at first non-assignment */
6727 break;
6728 eq++;
Denis Vlasenko6b06cb82008-05-15 21:30:45 +00006729 if (name_len == (unsigned)(eq - str)
Denys Vlasenko8eda4a92009-11-30 12:16:17 +01006730 && strncmp(str, name, name_len) == 0
6731 ) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006732 p = eq;
6733 /* goto value; - WRONG! */
6734 /* think "A=1 A=2 B=$A" */
6735 }
6736 var_str_list = var_str_list->next;
6737 } while (var_str_list);
6738 if (p)
6739 goto value;
6740 }
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006741 p = lookupvar(name);
6742 value:
6743 if (!p)
6744 return -1;
6745
6746 len = strlen(p);
6747 if (!(subtype == VSPLUS || subtype == VSLENGTH))
6748 memtodest(p, len, syntax, quotes);
6749 return len;
6750 }
6751
6752 if (subtype == VSPLUS || subtype == VSLENGTH)
6753 STADJUST(-len, expdest);
6754 return len;
6755}
6756
6757/*
6758 * Expand a variable, and return a pointer to the next character in the
6759 * input string.
6760 */
6761static char *
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006762evalvar(char *p, int flags, struct strlist *var_str_list)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006763{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006764 char varflags;
6765 char subtype;
6766 char quoted;
6767 char easy;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006768 char *var;
6769 int patloc;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006770 int startloc;
6771 ssize_t varlen;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006772
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006773 varflags = (unsigned char) *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006774 subtype = varflags & VSTYPE;
6775 quoted = varflags & VSQUOTE;
6776 var = p;
6777 easy = (!quoted || (*var == '@' && shellparam.nparam));
6778 startloc = expdest - (char *)stackblock();
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02006779 p = strchr(p, '=') + 1; //TODO: use var_end(p)?
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006780
6781 again:
Denys Vlasenkob0d63382009-09-16 16:18:32 +02006782 varlen = varvalue(var, varflags, flags, var_str_list);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006783 if (varflags & VSNUL)
6784 varlen--;
6785
6786 if (subtype == VSPLUS) {
6787 varlen = -1 - varlen;
6788 goto vsplus;
6789 }
6790
6791 if (subtype == VSMINUS) {
6792 vsplus:
6793 if (varlen < 0) {
6794 argstr(
Denys Vlasenko6040fe82010-09-12 15:03:16 +02006795 p,
6796 flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD),
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006797 var_str_list
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006798 );
6799 goto end;
6800 }
6801 if (easy)
6802 goto record;
6803 goto end;
6804 }
6805
6806 if (subtype == VSASSIGN || subtype == VSQUESTION) {
6807 if (varlen < 0) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006808 if (subevalvar(p, var, /* strloc: */ 0,
6809 subtype, startloc, varflags,
6810 /* quotes: */ 0,
6811 var_str_list)
6812 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006813 varflags &= ~VSNUL;
6814 /*
6815 * Remove any recorded regions beyond
6816 * start of variable
6817 */
6818 removerecordregions(startloc);
6819 goto again;
6820 }
6821 goto end;
6822 }
6823 if (easy)
6824 goto record;
6825 goto end;
6826 }
6827
6828 if (varlen < 0 && uflag)
6829 varunset(p, var, 0, 0);
6830
6831 if (subtype == VSLENGTH) {
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02006832 ssize_t n = varlen;
6833 if (n > 0) {
6834 reinit_unicode_for_ash();
6835 if (unicode_status == UNICODE_ON) {
6836 const char *val = lookupvar(var);
6837 n = unicode_strlen(val);
6838 }
6839 }
6840 cvtnum(n > 0 ? n : 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006841 goto record;
6842 }
6843
6844 if (subtype == VSNORMAL) {
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006845 if (easy)
6846 goto record;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006847 goto end;
6848 }
6849
6850#if DEBUG
6851 switch (subtype) {
6852 case VSTRIMLEFT:
6853 case VSTRIMLEFTMAX:
6854 case VSTRIMRIGHT:
6855 case VSTRIMRIGHTMAX:
Denis Vlasenko92e13c22008-03-25 01:17:40 +00006856#if ENABLE_ASH_BASH_COMPAT
6857 case VSSUBSTR:
6858 case VSREPLACE:
6859 case VSREPLACEALL:
6860#endif
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006861 break;
6862 default:
6863 abort();
6864 }
6865#endif
6866
6867 if (varlen >= 0) {
6868 /*
6869 * Terminate the string and start recording the pattern
6870 * right after it
6871 */
6872 STPUTC('\0', expdest);
6873 patloc = expdest - (char *)stackblock();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +02006874 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006875 startloc, varflags,
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02006876 /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR),
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006877 var_str_list)
6878 ) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006879 int amount = expdest - (
6880 (char *)stackblock() + patloc - 1
6881 );
6882 STADJUST(-amount, expdest);
6883 }
6884 /* Remove any recorded regions beyond start of variable */
6885 removerecordregions(startloc);
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00006886 record:
6887 recordregion(startloc, expdest - (char *)stackblock(), quoted);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006888 }
6889
6890 end:
6891 if (subtype != VSNORMAL) { /* skip to end of alternative */
6892 int nesting = 1;
6893 for (;;) {
Denys Vlasenkocd716832009-11-28 22:14:02 +01006894 unsigned char c = *p++;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006895 if (c == CTLESC)
6896 p++;
6897 else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
6898 if (varlen >= 0)
6899 argbackq = argbackq->next;
6900 } else if (c == CTLVAR) {
6901 if ((*p++ & VSTYPE) != VSNORMAL)
6902 nesting++;
6903 } else if (c == CTLENDVAR) {
6904 if (--nesting == 0)
6905 break;
6906 }
6907 }
6908 }
6909 return p;
6910}
6911
6912/*
6913 * Break the argument string into pieces based upon IFS and add the
6914 * strings to the argument list. The regions of the string to be
6915 * searched for IFS characters have been stored by recordregion.
6916 */
6917static void
6918ifsbreakup(char *string, struct arglist *arglist)
6919{
6920 struct ifsregion *ifsp;
6921 struct strlist *sp;
6922 char *start;
6923 char *p;
6924 char *q;
6925 const char *ifs, *realifs;
6926 int ifsspc;
6927 int nulonly;
6928
6929 start = string;
6930 if (ifslastp != NULL) {
6931 ifsspc = 0;
6932 nulonly = 0;
6933 realifs = ifsset() ? ifsval() : defifs;
6934 ifsp = &ifsfirst;
6935 do {
6936 p = string + ifsp->begoff;
6937 nulonly = ifsp->nulonly;
6938 ifs = nulonly ? nullstr : realifs;
6939 ifsspc = 0;
6940 while (p < string + ifsp->endoff) {
6941 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006942 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006943 p++;
6944 if (!strchr(ifs, *p)) {
6945 p++;
6946 continue;
6947 }
6948 if (!nulonly)
6949 ifsspc = (strchr(defifs, *p) != NULL);
6950 /* Ignore IFS whitespace at start */
6951 if (q == start && ifsspc) {
6952 p++;
6953 start = p;
6954 continue;
6955 }
6956 *q = '\0';
Denis Vlasenko597906c2008-02-20 16:38:54 +00006957 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006958 sp->text = start;
6959 *arglist->lastp = sp;
6960 arglist->lastp = &sp->next;
6961 p++;
6962 if (!nulonly) {
6963 for (;;) {
6964 if (p >= string + ifsp->endoff) {
6965 break;
6966 }
6967 q = p;
Denys Vlasenkocd716832009-11-28 22:14:02 +01006968 if ((unsigned char)*p == CTLESC)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006969 p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00006970 if (strchr(ifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006971 p = q;
6972 break;
Denis Vlasenko597906c2008-02-20 16:38:54 +00006973 }
6974 if (strchr(defifs, *p) == NULL) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006975 if (ifsspc) {
6976 p++;
6977 ifsspc = 0;
6978 } else {
6979 p = q;
6980 break;
6981 }
6982 } else
6983 p++;
6984 }
6985 }
6986 start = p;
6987 } /* while */
6988 ifsp = ifsp->next;
6989 } while (ifsp != NULL);
6990 if (nulonly)
6991 goto add;
6992 }
6993
6994 if (!*start)
6995 return;
6996
6997 add:
Denis Vlasenko597906c2008-02-20 16:38:54 +00006998 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00006999 sp->text = start;
7000 *arglist->lastp = sp;
7001 arglist->lastp = &sp->next;
7002}
7003
7004static void
7005ifsfree(void)
7006{
7007 struct ifsregion *p;
7008
7009 INT_OFF;
7010 p = ifsfirst.next;
7011 do {
7012 struct ifsregion *ifsp;
7013 ifsp = p->next;
7014 free(p);
7015 p = ifsp;
7016 } while (p);
7017 ifslastp = NULL;
7018 ifsfirst.next = NULL;
7019 INT_ON;
7020}
7021
7022/*
7023 * Add a file name to the list.
7024 */
7025static void
7026addfname(const char *name)
7027{
7028 struct strlist *sp;
7029
Denis Vlasenko597906c2008-02-20 16:38:54 +00007030 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007031 sp->text = ststrdup(name);
7032 *exparg.lastp = sp;
7033 exparg.lastp = &sp->next;
7034}
7035
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007036/*
7037 * Do metacharacter (i.e. *, ?, [...]) expansion.
7038 */
7039static void
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007040expmeta(char *expdir, char *enddir, char *name)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007041{
7042 char *p;
7043 const char *cp;
7044 char *start;
7045 char *endname;
7046 int metaflag;
7047 struct stat statb;
7048 DIR *dirp;
7049 struct dirent *dp;
7050 int atend;
7051 int matchdot;
7052
7053 metaflag = 0;
7054 start = name;
7055 for (p = name; *p; p++) {
7056 if (*p == '*' || *p == '?')
7057 metaflag = 1;
7058 else if (*p == '[') {
7059 char *q = p + 1;
7060 if (*q == '!')
7061 q++;
7062 for (;;) {
7063 if (*q == '\\')
7064 q++;
7065 if (*q == '/' || *q == '\0')
7066 break;
7067 if (*++q == ']') {
7068 metaflag = 1;
7069 break;
7070 }
7071 }
7072 } else if (*p == '\\')
7073 p++;
7074 else if (*p == '/') {
7075 if (metaflag)
7076 goto out;
7077 start = p + 1;
7078 }
7079 }
7080 out:
7081 if (metaflag == 0) { /* we've reached the end of the file name */
7082 if (enddir != expdir)
7083 metaflag++;
7084 p = name;
7085 do {
7086 if (*p == '\\')
7087 p++;
7088 *enddir++ = *p;
7089 } while (*p++);
7090 if (metaflag == 0 || lstat(expdir, &statb) >= 0)
7091 addfname(expdir);
7092 return;
7093 }
7094 endname = p;
7095 if (name < start) {
7096 p = name;
7097 do {
7098 if (*p == '\\')
7099 p++;
7100 *enddir++ = *p++;
7101 } while (p < start);
7102 }
7103 if (enddir == expdir) {
7104 cp = ".";
7105 } else if (enddir == expdir + 1 && *expdir == '/') {
7106 cp = "/";
7107 } else {
7108 cp = expdir;
7109 enddir[-1] = '\0';
7110 }
7111 dirp = opendir(cp);
7112 if (dirp == NULL)
7113 return;
7114 if (enddir != expdir)
7115 enddir[-1] = '/';
7116 if (*endname == 0) {
7117 atend = 1;
7118 } else {
7119 atend = 0;
7120 *endname++ = '\0';
7121 }
7122 matchdot = 0;
7123 p = start;
7124 if (*p == '\\')
7125 p++;
7126 if (*p == '.')
7127 matchdot++;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007128 while (!pending_int && (dp = readdir(dirp)) != NULL) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007129 if (dp->d_name[0] == '.' && !matchdot)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007130 continue;
7131 if (pmatch(start, dp->d_name)) {
7132 if (atend) {
7133 strcpy(enddir, dp->d_name);
7134 addfname(expdir);
7135 } else {
7136 for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';)
7137 continue;
7138 p[-1] = '/';
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007139 expmeta(expdir, p, endname);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007140 }
7141 }
7142 }
7143 closedir(dirp);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00007144 if (!atend)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007145 endname[-1] = '/';
7146}
7147
7148static struct strlist *
7149msort(struct strlist *list, int len)
7150{
7151 struct strlist *p, *q = NULL;
7152 struct strlist **lpp;
7153 int half;
7154 int n;
7155
7156 if (len <= 1)
7157 return list;
7158 half = len >> 1;
7159 p = list;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00007160 for (n = half; --n >= 0;) {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007161 q = p;
7162 p = p->next;
7163 }
7164 q->next = NULL; /* terminate first half of list */
7165 q = msort(list, half); /* sort first half of list */
7166 p = msort(p, len - half); /* sort second half */
7167 lpp = &list;
7168 for (;;) {
7169#if ENABLE_LOCALE_SUPPORT
7170 if (strcoll(p->text, q->text) < 0)
7171#else
7172 if (strcmp(p->text, q->text) < 0)
7173#endif
7174 {
7175 *lpp = p;
7176 lpp = &p->next;
7177 p = *lpp;
7178 if (p == NULL) {
7179 *lpp = q;
7180 break;
7181 }
7182 } else {
7183 *lpp = q;
7184 lpp = &q->next;
7185 q = *lpp;
7186 if (q == NULL) {
7187 *lpp = p;
7188 break;
7189 }
7190 }
7191 }
7192 return list;
7193}
7194
7195/*
7196 * Sort the results of file name expansion. It calculates the number of
7197 * strings to sort and then calls msort (short for merge sort) to do the
7198 * work.
7199 */
7200static struct strlist *
7201expsort(struct strlist *str)
7202{
7203 int len;
7204 struct strlist *sp;
7205
7206 len = 0;
7207 for (sp = str; sp; sp = sp->next)
7208 len++;
7209 return msort(str, len);
7210}
7211
7212static void
Denis Vlasenko68404f12008-03-17 09:00:54 +00007213expandmeta(struct strlist *str /*, int flag*/)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007214{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +00007215 static const char metachars[] ALIGN1 = {
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007216 '*', '?', '[', 0
7217 };
7218 /* TODO - EXP_REDIR */
7219
7220 while (str) {
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007221 char *expdir;
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007222 struct strlist **savelastp;
7223 struct strlist *sp;
7224 char *p;
7225
7226 if (fflag)
7227 goto nometa;
7228 if (!strpbrk(str->text, metachars))
7229 goto nometa;
7230 savelastp = exparg.lastp;
7231
7232 INT_OFF;
7233 p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7234 {
7235 int i = strlen(str->text);
7236 expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
7237 }
Denys Vlasenkofd33e172010-06-26 22:55:44 +02007238 expmeta(expdir, expdir, p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007239 free(expdir);
7240 if (p != str->text)
7241 free(p);
7242 INT_ON;
7243 if (exparg.lastp == savelastp) {
7244 /*
7245 * no matches
7246 */
7247 nometa:
7248 *exparg.lastp = str;
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007249 rmescapes(str->text, 0);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007250 exparg.lastp = &str->next;
7251 } else {
7252 *exparg.lastp = NULL;
7253 *savelastp = sp = expsort(*savelastp);
7254 while (sp->next != NULL)
7255 sp = sp->next;
7256 exparg.lastp = &sp->next;
7257 }
7258 str = str->next;
7259 }
7260}
7261
7262/*
7263 * Perform variable substitution and command substitution on an argument,
7264 * placing the resulting list of arguments in arglist. If EXP_FULL is true,
7265 * perform splitting and file name expansion. When arglist is NULL, perform
7266 * here document expansion.
7267 */
7268static void
7269expandarg(union node *arg, struct arglist *arglist, int flag)
7270{
7271 struct strlist *sp;
7272 char *p;
7273
7274 argbackq = arg->narg.backquote;
7275 STARTSTACKSTR(expdest);
7276 ifsfirst.next = NULL;
7277 ifslastp = NULL;
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007278 TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag));
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007279 argstr(arg->narg.text, flag,
7280 /* var_str_list: */ arglist ? arglist->list : NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007281 p = _STPUTC('\0', expdest);
7282 expdest = p - 1;
7283 if (arglist == NULL) {
7284 return; /* here document expanded */
7285 }
7286 p = grabstackstr(p);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007287 TRACE(("expandarg: p:'%s'\n", p));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007288 exparg.lastp = &exparg.list;
7289 /*
7290 * TODO - EXP_REDIR
7291 */
7292 if (flag & EXP_FULL) {
7293 ifsbreakup(p, &exparg);
7294 *exparg.lastp = NULL;
7295 exparg.lastp = &exparg.list;
Denis Vlasenko68404f12008-03-17 09:00:54 +00007296 expandmeta(exparg.list /*, flag*/);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007297 } else {
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007298 if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */
Denys Vlasenkob6c84342009-08-29 20:23:20 +02007299 rmescapes(p, 0);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02007300 TRACE(("expandarg: rmescapes:'%s'\n", p));
7301 }
Denis Vlasenko597906c2008-02-20 16:38:54 +00007302 sp = stzalloc(sizeof(*sp));
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007303 sp->text = p;
7304 *exparg.lastp = sp;
7305 exparg.lastp = &sp->next;
7306 }
7307 if (ifsfirst.next)
7308 ifsfree();
7309 *exparg.lastp = NULL;
7310 if (exparg.list) {
7311 *arglist->lastp = exparg.list;
7312 arglist->lastp = exparg.lastp;
7313 }
7314}
7315
7316/*
7317 * Expand shell variables and backquotes inside a here document.
7318 */
7319static void
7320expandhere(union node *arg, int fd)
7321{
7322 herefd = fd;
7323 expandarg(arg, (struct arglist *)NULL, 0);
7324 full_write(fd, stackblock(), expdest - (char *)stackblock());
7325}
7326
7327/*
7328 * Returns true if the pattern matches the string.
7329 */
7330static int
7331patmatch(char *pattern, const char *string)
7332{
7333 return pmatch(preglob(pattern, 0, 0), string);
7334}
7335
7336/*
7337 * See if a pattern matches in a case statement.
7338 */
7339static int
7340casematch(union node *pattern, char *val)
7341{
7342 struct stackmark smark;
7343 int result;
7344
7345 setstackmark(&smark);
7346 argbackq = pattern->narg.backquote;
7347 STARTSTACKSTR(expdest);
7348 ifslastp = NULL;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00007349 argstr(pattern->narg.text, EXP_TILDE | EXP_CASE,
7350 /* var_str_list: */ NULL);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00007351 STACKSTRNUL(expdest);
7352 result = patmatch(stackblock(), val);
7353 popstackmark(&smark);
7354 return result;
7355}
7356
7357
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007358/* ============ find_command */
7359
7360struct builtincmd {
7361 const char *name;
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007362 int (*builtin)(int, char **) FAST_FUNC;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007363 /* unsigned flags; */
7364};
7365#define IS_BUILTIN_SPECIAL(b) ((b)->name[0] & 1)
Denis Vlasenkoe26b2782008-02-12 07:40:29 +00007366/* "regular" builtins always take precedence over commands,
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007367 * regardless of PATH=....%builtin... position */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007368#define IS_BUILTIN_REGULAR(b) ((b)->name[0] & 2)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007369#define IS_BUILTIN_ASSIGN(b) ((b)->name[0] & 4)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007370
7371struct cmdentry {
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007372 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007373 union param {
7374 int index;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007375 /* index >= 0 for commands without path (slashes) */
7376 /* (TODO: what exactly does the value mean? PATH position?) */
7377 /* index == -1 for commands with slashes */
7378 /* index == (-2 - applet_no) for NOFORK applets */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007379 const struct builtincmd *cmd;
7380 struct funcnode *func;
7381 } u;
7382};
7383/* values of cmdtype */
7384#define CMDUNKNOWN -1 /* no entry in table for command */
7385#define CMDNORMAL 0 /* command is an executable program */
7386#define CMDFUNCTION 1 /* command is a shell function */
7387#define CMDBUILTIN 2 /* command is a shell builtin */
7388
7389/* action to find_command() */
7390#define DO_ERR 0x01 /* prints errors */
7391#define DO_ABS 0x02 /* checks absolute paths */
7392#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
7393#define DO_ALTPATH 0x08 /* using alternate path */
7394#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
7395
7396static void find_command(char *, struct cmdentry *, int, const char *);
7397
7398
7399/* ============ Hashing commands */
7400
7401/*
7402 * When commands are first encountered, they are entered in a hash table.
7403 * This ensures that a full path search will not have to be done for them
7404 * on each invocation.
7405 *
7406 * We should investigate converting to a linear search, even though that
7407 * would make the command name "hash" a misnomer.
7408 */
7409
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007410struct tblentry {
7411 struct tblentry *next; /* next entry in hash chain */
7412 union param param; /* definition of builtin function */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007413 smallint cmdtype; /* CMDxxx */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007414 char rehash; /* if set, cd done since entry created */
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007415 char cmdname[1]; /* name of command */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007416};
7417
Denis Vlasenko01631112007-12-16 17:20:38 +00007418static struct tblentry **cmdtable;
7419#define INIT_G_cmdtable() do { \
7420 cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \
7421} while (0)
7422
7423static int builtinloc = -1; /* index in path of %builtin, or -1 */
7424
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007425
7426static void
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007427tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007428{
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007429#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007430 if (applet_no >= 0) {
Denis Vlasenkob7304742008-10-20 08:15:51 +00007431 if (APPLET_IS_NOEXEC(applet_no)) {
Denys Vlasenko7df28bb2010-06-18 14:23:47 +02007432 clearenv();
Denis Vlasenkob7304742008-10-20 08:15:51 +00007433 while (*envp)
7434 putenv(*envp++);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007435 run_applet_no_and_exit(applet_no, argv);
Denis Vlasenkob7304742008-10-20 08:15:51 +00007436 }
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007437 /* re-exec ourselves with the new arguments */
7438 execve(bb_busybox_exec_path, argv, envp);
7439 /* If they called chroot or otherwise made the binary no longer
7440 * executable, fall through */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007441 }
7442#endif
7443
7444 repeat:
7445#ifdef SYSV
7446 do {
7447 execve(cmd, argv, envp);
7448 } while (errno == EINTR);
7449#else
7450 execve(cmd, argv, envp);
7451#endif
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007452 if (cmd == (char*) bb_busybox_exec_path) {
7453 /* We already visited ENOEXEC branch below, don't do it again */
7454//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up?
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007455 free(argv);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007456 return;
7457 }
7458 if (errno == ENOEXEC) {
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007459 /* Run "cmd" as a shell script:
7460 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html
7461 * "If the execve() function fails with ENOEXEC, the shell
7462 * shall execute a command equivalent to having a shell invoked
7463 * with the command name as its first operand,
7464 * with any remaining arguments passed to the new shell"
7465 *
7466 * That is, do not use $SHELL, user's shell, or /bin/sh;
7467 * just call ourselves.
Denys Vlasenko2bef5262011-12-16 00:25:17 +01007468 *
7469 * Note that bash reads ~80 chars of the file, and if it sees
7470 * a zero byte before it sees newline, it doesn't try to
7471 * interpret it, but fails with "cannot execute binary file"
Denys Vlasenkocda6ea92011-12-16 00:44:36 +01007472 * message and exit code 126. For one, this prevents attempts
7473 * to interpret foreign ELF binaries as shell scripts.
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007474 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007475 char **ap;
7476 char **new;
7477
7478 for (ap = argv; *ap; ap++)
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007479 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007480 new = ckmalloc((ap - argv + 2) * sizeof(new[0]));
7481 new[0] = (char*) "ash";
7482 new[1] = cmd;
7483 ap = new + 2;
7484 while ((*ap++ = *++argv) != NULL)
Denis Vlasenko597906c2008-02-20 16:38:54 +00007485 continue;
Denys Vlasenkoaefe1c22011-03-07 12:02:40 +01007486 cmd = (char*) bb_busybox_exec_path;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007487 argv = new;
7488 goto repeat;
7489 }
7490}
7491
7492/*
7493 * Exec a program. Never returns. If you change this routine, you may
7494 * have to change the find_command routine as well.
7495 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007496static void shellexec(char **, const char *, int) NORETURN;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007497static void
7498shellexec(char **argv, const char *path, int idx)
7499{
7500 char *cmdname;
7501 int e;
7502 char **envp;
7503 int exerrno;
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007504 int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007505
Denis Vlasenko34c73c42008-08-16 11:48:02 +00007506 clearredir(/*drop:*/ 1);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +02007507 envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL);
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007508 if (strchr(argv[0], '/') != NULL
Denis Vlasenko80d14be2007-04-10 23:03:30 +00007509#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko4a9ca132008-04-12 20:07:08 +00007510 || (applet_no = find_applet_by_name(argv[0])) >= 0
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007511#endif
7512 ) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007513 tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007514 if (applet_no >= 0) {
7515 /* We tried execing ourself, but it didn't work.
7516 * Maybe /proc/self/exe doesn't exist?
7517 * Try $PATH search.
7518 */
7519 goto try_PATH;
7520 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007521 e = errno;
7522 } else {
Denys Vlasenko83f103b2011-12-20 06:10:35 +01007523 try_PATH:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007524 e = ENOENT;
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007525 while ((cmdname = path_advance(&path, argv[0])) != NULL) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007526 if (--idx < 0 && pathopt == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +00007527 tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007528 if (errno != ENOENT && errno != ENOTDIR)
7529 e = errno;
7530 }
7531 stunalloc(cmdname);
7532 }
7533 }
7534
7535 /* Map to POSIX errors */
7536 switch (e) {
7537 case EACCES:
7538 exerrno = 126;
7539 break;
7540 case ENOENT:
7541 exerrno = 127;
7542 break;
7543 default:
7544 exerrno = 2;
7545 break;
7546 }
7547 exitstatus = exerrno;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02007548 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
7549 argv[0], e, suppress_int));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007550 ash_msg_and_raise(EXEXEC, "%s: %s", argv[0], errmsg(e, "not found"));
7551 /* NOTREACHED */
7552}
7553
7554static void
7555printentry(struct tblentry *cmdp)
7556{
7557 int idx;
7558 const char *path;
7559 char *name;
7560
7561 idx = cmdp->param.index;
7562 path = pathval();
7563 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007564 name = path_advance(&path, cmdp->cmdname);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007565 stunalloc(name);
7566 } while (--idx >= 0);
7567 out1fmt("%s%s\n", name, (cmdp->rehash ? "*" : nullstr));
7568}
7569
7570/*
7571 * Clear out command entries. The argument specifies the first entry in
7572 * PATH which has changed.
7573 */
7574static void
7575clearcmdentry(int firstchange)
7576{
7577 struct tblentry **tblp;
7578 struct tblentry **pp;
7579 struct tblentry *cmdp;
7580
7581 INT_OFF;
7582 for (tblp = cmdtable; tblp < &cmdtable[CMDTABLESIZE]; tblp++) {
7583 pp = tblp;
7584 while ((cmdp = *pp) != NULL) {
7585 if ((cmdp->cmdtype == CMDNORMAL &&
7586 cmdp->param.index >= firstchange)
7587 || (cmdp->cmdtype == CMDBUILTIN &&
7588 builtinloc >= firstchange)
7589 ) {
7590 *pp = cmdp->next;
7591 free(cmdp);
7592 } else {
7593 pp = &cmdp->next;
7594 }
7595 }
7596 }
7597 INT_ON;
7598}
7599
7600/*
7601 * Locate a command in the command hash table. If "add" is nonzero,
7602 * add the command to the table if it is not already present. The
7603 * variable "lastcmdentry" is set to point to the address of the link
7604 * pointing to the entry, so that delete_cmd_entry can delete the
7605 * entry.
7606 *
7607 * Interrupts must be off if called with add != 0.
7608 */
7609static struct tblentry **lastcmdentry;
7610
7611static struct tblentry *
7612cmdlookup(const char *name, int add)
7613{
7614 unsigned int hashval;
7615 const char *p;
7616 struct tblentry *cmdp;
7617 struct tblentry **pp;
7618
7619 p = name;
7620 hashval = (unsigned char)*p << 4;
7621 while (*p)
7622 hashval += (unsigned char)*p++;
7623 hashval &= 0x7FFF;
7624 pp = &cmdtable[hashval % CMDTABLESIZE];
7625 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7626 if (strcmp(cmdp->cmdname, name) == 0)
7627 break;
7628 pp = &cmdp->next;
7629 }
7630 if (add && cmdp == NULL) {
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007631 cmdp = *pp = ckzalloc(sizeof(struct tblentry)
7632 + strlen(name)
7633 /* + 1 - already done because
7634 * tblentry::cmdname is char[1] */);
Denis Vlasenko597906c2008-02-20 16:38:54 +00007635 /*cmdp->next = NULL; - ckzalloc did it */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007636 cmdp->cmdtype = CMDUNKNOWN;
7637 strcpy(cmdp->cmdname, name);
7638 }
7639 lastcmdentry = pp;
7640 return cmdp;
7641}
7642
7643/*
7644 * Delete the command entry returned on the last lookup.
7645 */
7646static void
7647delete_cmd_entry(void)
7648{
7649 struct tblentry *cmdp;
7650
7651 INT_OFF;
7652 cmdp = *lastcmdentry;
7653 *lastcmdentry = cmdp->next;
7654 if (cmdp->cmdtype == CMDFUNCTION)
7655 freefunc(cmdp->param.func);
7656 free(cmdp);
7657 INT_ON;
7658}
7659
7660/*
7661 * Add a new command entry, replacing any existing command entry for
7662 * the same name - except special builtins.
7663 */
7664static void
7665addcmdentry(char *name, struct cmdentry *entry)
7666{
7667 struct tblentry *cmdp;
7668
7669 cmdp = cmdlookup(name, 1);
7670 if (cmdp->cmdtype == CMDFUNCTION) {
7671 freefunc(cmdp->param.func);
7672 }
7673 cmdp->cmdtype = entry->cmdtype;
7674 cmdp->param = entry->u;
7675 cmdp->rehash = 0;
7676}
7677
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007678static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007679hashcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007680{
7681 struct tblentry **pp;
7682 struct tblentry *cmdp;
7683 int c;
7684 struct cmdentry entry;
7685 char *name;
7686
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007687 if (nextopt("r") != '\0') {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007688 clearcmdentry(0);
7689 return 0;
7690 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007691
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007692 if (*argptr == NULL) {
7693 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7694 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
7695 if (cmdp->cmdtype == CMDNORMAL)
7696 printentry(cmdp);
7697 }
7698 }
7699 return 0;
7700 }
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007701
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007702 c = 0;
7703 while ((name = *argptr) != NULL) {
7704 cmdp = cmdlookup(name, 0);
7705 if (cmdp != NULL
7706 && (cmdp->cmdtype == CMDNORMAL
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007707 || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))
7708 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007709 delete_cmd_entry();
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007710 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007711 find_command(name, &entry, DO_ERR, pathval());
7712 if (entry.cmdtype == CMDUNKNOWN)
7713 c = 1;
7714 argptr++;
7715 }
7716 return c;
7717}
7718
7719/*
7720 * Called when a cd is done. Marks all commands so the next time they
7721 * are executed they will be rehashed.
7722 */
7723static void
7724hashcd(void)
7725{
7726 struct tblentry **pp;
7727 struct tblentry *cmdp;
7728
7729 for (pp = cmdtable; pp < &cmdtable[CMDTABLESIZE]; pp++) {
7730 for (cmdp = *pp; cmdp; cmdp = cmdp->next) {
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007731 if (cmdp->cmdtype == CMDNORMAL
7732 || (cmdp->cmdtype == CMDBUILTIN
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02007733 && !IS_BUILTIN_REGULAR(cmdp->param.cmd)
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007734 && builtinloc > 0)
7735 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007736 cmdp->rehash = 1;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007737 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007738 }
7739 }
7740}
7741
7742/*
7743 * Fix command hash table when PATH changed.
7744 * Called before PATH is changed. The argument is the new value of PATH;
7745 * pathval() still returns the old value at this point.
7746 * Called with interrupts off.
7747 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007748static void FAST_FUNC
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007749changepath(const char *new)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007750{
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007751 const char *old;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007752 int firstchange;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007753 int idx;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007754 int idx_bltin;
7755
7756 old = pathval();
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007757 firstchange = 9999; /* assume no change */
7758 idx = 0;
7759 idx_bltin = -1;
7760 for (;;) {
7761 if (*old != *new) {
7762 firstchange = idx;
7763 if ((*old == '\0' && *new == ':')
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007764 || (*old == ':' && *new == '\0')
7765 ) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007766 firstchange++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007767 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007768 old = new; /* ignore subsequent differences */
7769 }
7770 if (*new == '\0')
7771 break;
7772 if (*new == '%' && idx_bltin < 0 && prefix(new + 1, "builtin"))
7773 idx_bltin = idx;
Denis Vlasenko5c3d2b32008-02-03 22:01:08 +00007774 if (*new == ':')
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007775 idx++;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +02007776 new++;
7777 old++;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007778 }
7779 if (builtinloc < 0 && idx_bltin >= 0)
7780 builtinloc = idx_bltin; /* zap builtins */
7781 if (builtinloc >= 0 && idx_bltin < 0)
7782 firstchange = 0;
7783 clearcmdentry(firstchange);
7784 builtinloc = idx_bltin;
7785}
7786
7787#define TEOF 0
7788#define TNL 1
7789#define TREDIR 2
7790#define TWORD 3
7791#define TSEMI 4
7792#define TBACKGND 5
7793#define TAND 6
7794#define TOR 7
7795#define TPIPE 8
7796#define TLP 9
7797#define TRP 10
7798#define TENDCASE 11
7799#define TENDBQUOTE 12
7800#define TNOT 13
7801#define TCASE 14
7802#define TDO 15
7803#define TDONE 16
7804#define TELIF 17
7805#define TELSE 18
7806#define TESAC 19
7807#define TFI 20
7808#define TFOR 21
7809#define TIF 22
7810#define TIN 23
7811#define TTHEN 24
7812#define TUNTIL 25
7813#define TWHILE 26
7814#define TBEGIN 27
7815#define TEND 28
Denis Vlasenkob07a4962008-06-22 13:16:23 +00007816typedef smallint token_id_t;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007817
7818/* first char is indicating which tokens mark the end of a list */
7819static const char *const tokname_array[] = {
7820 "\1end of file",
7821 "\0newline",
7822 "\0redirection",
7823 "\0word",
7824 "\0;",
7825 "\0&",
7826 "\0&&",
7827 "\0||",
7828 "\0|",
7829 "\0(",
7830 "\1)",
7831 "\1;;",
7832 "\1`",
7833#define KWDOFFSET 13
7834 /* the following are keywords */
7835 "\0!",
7836 "\0case",
7837 "\1do",
7838 "\1done",
7839 "\1elif",
7840 "\1else",
7841 "\1esac",
7842 "\1fi",
7843 "\0for",
7844 "\0if",
7845 "\0in",
7846 "\1then",
7847 "\0until",
7848 "\0while",
7849 "\0{",
7850 "\1}",
7851};
7852
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007853/* Wrapper around strcmp for qsort/bsearch/... */
7854static int
7855pstrcmp(const void *a, const void *b)
7856{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00007857 return strcmp((char*) a, (*(char**) b) + 1);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007858}
7859
7860static const char *const *
7861findkwd(const char *s)
7862{
7863 return bsearch(s, tokname_array + KWDOFFSET,
Denis Vlasenko80b8b392007-06-25 10:55:35 +00007864 ARRAY_SIZE(tokname_array) - KWDOFFSET,
7865 sizeof(tokname_array[0]), pstrcmp);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007866}
7867
7868/*
7869 * Locate and print what a word is...
7870 */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007871static int
7872describe_command(char *command, int describe_command_verbose)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007873{
7874 struct cmdentry entry;
7875 struct tblentry *cmdp;
7876#if ENABLE_ASH_ALIAS
7877 const struct alias *ap;
7878#endif
7879 const char *path = pathval();
7880
7881 if (describe_command_verbose) {
7882 out1str(command);
7883 }
7884
7885 /* First look at the keywords */
7886 if (findkwd(command)) {
7887 out1str(describe_command_verbose ? " is a shell keyword" : command);
7888 goto out;
7889 }
7890
7891#if ENABLE_ASH_ALIAS
7892 /* Then look at the aliases */
7893 ap = lookupalias(command, 0);
7894 if (ap != NULL) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007895 if (!describe_command_verbose) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007896 out1str("alias ");
7897 printalias(ap);
7898 return 0;
7899 }
Denis Vlasenko46846e22007-05-20 13:08:31 +00007900 out1fmt(" is an alias for %s", ap->val);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007901 goto out;
7902 }
7903#endif
7904 /* Then check if it is a tracked alias */
7905 cmdp = cmdlookup(command, 0);
7906 if (cmdp != NULL) {
7907 entry.cmdtype = cmdp->cmdtype;
7908 entry.u = cmdp->param;
7909 } else {
7910 /* Finally use brute force */
7911 find_command(command, &entry, DO_ABS, path);
7912 }
7913
7914 switch (entry.cmdtype) {
7915 case CMDNORMAL: {
7916 int j = entry.u.index;
7917 char *p;
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00007918 if (j < 0) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007919 p = command;
7920 } else {
7921 do {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +02007922 p = path_advance(&path, command);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007923 stunalloc(p);
7924 } while (--j >= 0);
7925 }
7926 if (describe_command_verbose) {
7927 out1fmt(" is%s %s",
7928 (cmdp ? " a tracked alias for" : nullstr), p
7929 );
7930 } else {
7931 out1str(p);
7932 }
7933 break;
7934 }
7935
7936 case CMDFUNCTION:
7937 if (describe_command_verbose) {
7938 out1str(" is a shell function");
7939 } else {
7940 out1str(command);
7941 }
7942 break;
7943
7944 case CMDBUILTIN:
7945 if (describe_command_verbose) {
7946 out1fmt(" is a %sshell builtin",
7947 IS_BUILTIN_SPECIAL(entry.u.cmd) ?
7948 "special " : nullstr
7949 );
7950 } else {
7951 out1str(command);
7952 }
7953 break;
7954
7955 default:
7956 if (describe_command_verbose) {
7957 out1str(": not found\n");
7958 }
7959 return 127;
7960 }
7961 out:
Denys Vlasenko285ad152009-12-04 23:02:27 +01007962 out1str("\n");
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007963 return 0;
7964}
7965
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007966static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007967typecmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007968{
Denis Vlasenko46846e22007-05-20 13:08:31 +00007969 int i = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007970 int err = 0;
Denis Vlasenko46846e22007-05-20 13:08:31 +00007971 int verbose = 1;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007972
Denis Vlasenko46846e22007-05-20 13:08:31 +00007973 /* type -p ... ? (we don't bother checking for 'p') */
Denis Vlasenko1fc62382007-06-25 22:55:34 +00007974 if (argv[1] && argv[1][0] == '-') {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007975 i++;
7976 verbose = 0;
7977 }
Denis Vlasenko68404f12008-03-17 09:00:54 +00007978 while (argv[i]) {
Denis Vlasenko46846e22007-05-20 13:08:31 +00007979 err |= describe_command(argv[i++], verbose);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007980 }
7981 return err;
7982}
7983
7984#if ENABLE_ASH_CMDCMD
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02007985static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00007986commandcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00007987{
7988 int c;
7989 enum {
7990 VERIFY_BRIEF = 1,
7991 VERIFY_VERBOSE = 2,
7992 } verify = 0;
7993
7994 while ((c = nextopt("pvV")) != '\0')
7995 if (c == 'V')
7996 verify |= VERIFY_VERBOSE;
7997 else if (c == 'v')
7998 verify |= VERIFY_BRIEF;
7999#if DEBUG
8000 else if (c != 'p')
8001 abort();
8002#endif
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008003 /* Mimic bash: just "command -v" doesn't complain, it's a nop */
8004 if (verify && (*argptr != NULL)) {
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008005 return describe_command(*argptr, verify - VERIFY_BRIEF);
Denis Vlasenkoe7067e32008-07-11 23:09:34 +00008006 }
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008007
8008 return 0;
8009}
8010#endif
8011
8012
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008013/* ============ eval.c */
Eric Andersencb57d552001-06-28 07:25:16 +00008014
Denis Vlasenko340299a2008-11-21 10:36:36 +00008015static int funcblocksize; /* size of structures in function */
8016static int funcstringsize; /* size of strings in node */
8017static void *funcblock; /* block to allocate function from */
8018static char *funcstring; /* block to allocate strings from */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008019
Eric Andersencb57d552001-06-28 07:25:16 +00008020/* flags in argument to evaltree */
Denis Vlasenko340299a2008-11-21 10:36:36 +00008021#define EV_EXIT 01 /* exit after evaluating tree */
8022#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
Eric Andersenc470f442003-07-28 09:56:35 +00008023#define EV_BACKCMD 04 /* command executing within back quotes */
Eric Andersencb57d552001-06-28 07:25:16 +00008024
Denys Vlasenko0e5e4ea2009-10-11 00:36:20 +02008025static const uint8_t nodesize[N_NUMBER] = {
Denis Vlasenko340299a2008-11-21 10:36:36 +00008026 [NCMD ] = SHELL_ALIGN(sizeof(struct ncmd)),
8027 [NPIPE ] = SHELL_ALIGN(sizeof(struct npipe)),
8028 [NREDIR ] = SHELL_ALIGN(sizeof(struct nredir)),
8029 [NBACKGND ] = SHELL_ALIGN(sizeof(struct nredir)),
8030 [NSUBSHELL] = SHELL_ALIGN(sizeof(struct nredir)),
8031 [NAND ] = SHELL_ALIGN(sizeof(struct nbinary)),
8032 [NOR ] = SHELL_ALIGN(sizeof(struct nbinary)),
8033 [NSEMI ] = SHELL_ALIGN(sizeof(struct nbinary)),
8034 [NIF ] = SHELL_ALIGN(sizeof(struct nif)),
8035 [NWHILE ] = SHELL_ALIGN(sizeof(struct nbinary)),
8036 [NUNTIL ] = SHELL_ALIGN(sizeof(struct nbinary)),
8037 [NFOR ] = SHELL_ALIGN(sizeof(struct nfor)),
8038 [NCASE ] = SHELL_ALIGN(sizeof(struct ncase)),
8039 [NCLIST ] = SHELL_ALIGN(sizeof(struct nclist)),
8040 [NDEFUN ] = SHELL_ALIGN(sizeof(struct narg)),
8041 [NARG ] = SHELL_ALIGN(sizeof(struct narg)),
8042 [NTO ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008043#if ENABLE_ASH_BASH_COMPAT
Denis Vlasenko340299a2008-11-21 10:36:36 +00008044 [NTO2 ] = SHELL_ALIGN(sizeof(struct nfile)),
Denis Vlasenkocc5feab2008-11-22 01:32:40 +00008045#endif
Denis Vlasenko340299a2008-11-21 10:36:36 +00008046 [NCLOBBER ] = SHELL_ALIGN(sizeof(struct nfile)),
8047 [NFROM ] = SHELL_ALIGN(sizeof(struct nfile)),
8048 [NFROMTO ] = SHELL_ALIGN(sizeof(struct nfile)),
8049 [NAPPEND ] = SHELL_ALIGN(sizeof(struct nfile)),
8050 [NTOFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8051 [NFROMFD ] = SHELL_ALIGN(sizeof(struct ndup)),
8052 [NHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8053 [NXHERE ] = SHELL_ALIGN(sizeof(struct nhere)),
8054 [NNOT ] = SHELL_ALIGN(sizeof(struct nnot)),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008055};
8056
8057static void calcsize(union node *n);
8058
8059static void
8060sizenodelist(struct nodelist *lp)
8061{
8062 while (lp) {
8063 funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
8064 calcsize(lp->n);
8065 lp = lp->next;
8066 }
8067}
8068
8069static void
8070calcsize(union node *n)
8071{
8072 if (n == NULL)
8073 return;
8074 funcblocksize += nodesize[n->type];
8075 switch (n->type) {
8076 case NCMD:
8077 calcsize(n->ncmd.redirect);
8078 calcsize(n->ncmd.args);
8079 calcsize(n->ncmd.assign);
8080 break;
8081 case NPIPE:
8082 sizenodelist(n->npipe.cmdlist);
8083 break;
8084 case NREDIR:
8085 case NBACKGND:
8086 case NSUBSHELL:
8087 calcsize(n->nredir.redirect);
8088 calcsize(n->nredir.n);
8089 break;
8090 case NAND:
8091 case NOR:
8092 case NSEMI:
8093 case NWHILE:
8094 case NUNTIL:
8095 calcsize(n->nbinary.ch2);
8096 calcsize(n->nbinary.ch1);
8097 break;
8098 case NIF:
8099 calcsize(n->nif.elsepart);
8100 calcsize(n->nif.ifpart);
8101 calcsize(n->nif.test);
8102 break;
8103 case NFOR:
8104 funcstringsize += strlen(n->nfor.var) + 1;
8105 calcsize(n->nfor.body);
8106 calcsize(n->nfor.args);
8107 break;
8108 case NCASE:
8109 calcsize(n->ncase.cases);
8110 calcsize(n->ncase.expr);
8111 break;
8112 case NCLIST:
8113 calcsize(n->nclist.body);
8114 calcsize(n->nclist.pattern);
8115 calcsize(n->nclist.next);
8116 break;
8117 case NDEFUN:
8118 case NARG:
8119 sizenodelist(n->narg.backquote);
8120 funcstringsize += strlen(n->narg.text) + 1;
8121 calcsize(n->narg.next);
8122 break;
8123 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008124#if ENABLE_ASH_BASH_COMPAT
8125 case NTO2:
8126#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008127 case NCLOBBER:
8128 case NFROM:
8129 case NFROMTO:
8130 case NAPPEND:
8131 calcsize(n->nfile.fname);
8132 calcsize(n->nfile.next);
8133 break;
8134 case NTOFD:
8135 case NFROMFD:
8136 calcsize(n->ndup.vname);
8137 calcsize(n->ndup.next);
8138 break;
8139 case NHERE:
8140 case NXHERE:
8141 calcsize(n->nhere.doc);
8142 calcsize(n->nhere.next);
8143 break;
8144 case NNOT:
8145 calcsize(n->nnot.com);
8146 break;
8147 };
8148}
8149
8150static char *
8151nodeckstrdup(char *s)
8152{
8153 char *rtn = funcstring;
8154
8155 strcpy(funcstring, s);
8156 funcstring += strlen(s) + 1;
8157 return rtn;
8158}
8159
8160static union node *copynode(union node *);
8161
8162static struct nodelist *
8163copynodelist(struct nodelist *lp)
8164{
8165 struct nodelist *start;
8166 struct nodelist **lpp;
8167
8168 lpp = &start;
8169 while (lp) {
8170 *lpp = funcblock;
8171 funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
8172 (*lpp)->n = copynode(lp->n);
8173 lp = lp->next;
8174 lpp = &(*lpp)->next;
8175 }
8176 *lpp = NULL;
8177 return start;
8178}
8179
8180static union node *
8181copynode(union node *n)
8182{
8183 union node *new;
8184
8185 if (n == NULL)
8186 return NULL;
8187 new = funcblock;
8188 funcblock = (char *) funcblock + nodesize[n->type];
8189
8190 switch (n->type) {
8191 case NCMD:
8192 new->ncmd.redirect = copynode(n->ncmd.redirect);
8193 new->ncmd.args = copynode(n->ncmd.args);
8194 new->ncmd.assign = copynode(n->ncmd.assign);
8195 break;
8196 case NPIPE:
8197 new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008198 new->npipe.pipe_backgnd = n->npipe.pipe_backgnd;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008199 break;
8200 case NREDIR:
8201 case NBACKGND:
8202 case NSUBSHELL:
8203 new->nredir.redirect = copynode(n->nredir.redirect);
8204 new->nredir.n = copynode(n->nredir.n);
8205 break;
8206 case NAND:
8207 case NOR:
8208 case NSEMI:
8209 case NWHILE:
8210 case NUNTIL:
8211 new->nbinary.ch2 = copynode(n->nbinary.ch2);
8212 new->nbinary.ch1 = copynode(n->nbinary.ch1);
8213 break;
8214 case NIF:
8215 new->nif.elsepart = copynode(n->nif.elsepart);
8216 new->nif.ifpart = copynode(n->nif.ifpart);
8217 new->nif.test = copynode(n->nif.test);
8218 break;
8219 case NFOR:
8220 new->nfor.var = nodeckstrdup(n->nfor.var);
8221 new->nfor.body = copynode(n->nfor.body);
8222 new->nfor.args = copynode(n->nfor.args);
8223 break;
8224 case NCASE:
8225 new->ncase.cases = copynode(n->ncase.cases);
8226 new->ncase.expr = copynode(n->ncase.expr);
8227 break;
8228 case NCLIST:
8229 new->nclist.body = copynode(n->nclist.body);
8230 new->nclist.pattern = copynode(n->nclist.pattern);
8231 new->nclist.next = copynode(n->nclist.next);
8232 break;
8233 case NDEFUN:
8234 case NARG:
8235 new->narg.backquote = copynodelist(n->narg.backquote);
8236 new->narg.text = nodeckstrdup(n->narg.text);
8237 new->narg.next = copynode(n->narg.next);
8238 break;
8239 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008240#if ENABLE_ASH_BASH_COMPAT
8241 case NTO2:
8242#endif
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008243 case NCLOBBER:
8244 case NFROM:
8245 case NFROMTO:
8246 case NAPPEND:
8247 new->nfile.fname = copynode(n->nfile.fname);
8248 new->nfile.fd = n->nfile.fd;
8249 new->nfile.next = copynode(n->nfile.next);
8250 break;
8251 case NTOFD:
8252 case NFROMFD:
8253 new->ndup.vname = copynode(n->ndup.vname);
8254 new->ndup.dupfd = n->ndup.dupfd;
8255 new->ndup.fd = n->ndup.fd;
8256 new->ndup.next = copynode(n->ndup.next);
8257 break;
8258 case NHERE:
8259 case NXHERE:
8260 new->nhere.doc = copynode(n->nhere.doc);
8261 new->nhere.fd = n->nhere.fd;
8262 new->nhere.next = copynode(n->nhere.next);
8263 break;
8264 case NNOT:
8265 new->nnot.com = copynode(n->nnot.com);
8266 break;
8267 };
8268 new->type = n->type;
8269 return new;
8270}
8271
8272/*
8273 * Make a copy of a parse tree.
8274 */
8275static struct funcnode *
8276copyfunc(union node *n)
8277{
8278 struct funcnode *f;
8279 size_t blocksize;
8280
8281 funcblocksize = offsetof(struct funcnode, n);
8282 funcstringsize = 0;
8283 calcsize(n);
8284 blocksize = funcblocksize;
8285 f = ckmalloc(blocksize + funcstringsize);
8286 funcblock = (char *) f + offsetof(struct funcnode, n);
8287 funcstring = (char *) f + blocksize;
8288 copynode(n);
8289 f->count = 0;
8290 return f;
8291}
8292
8293/*
8294 * Define a shell function.
8295 */
8296static void
8297defun(char *name, union node *func)
8298{
8299 struct cmdentry entry;
8300
8301 INT_OFF;
8302 entry.cmdtype = CMDFUNCTION;
8303 entry.u.func = copyfunc(func);
8304 addcmdentry(name, &entry);
8305 INT_ON;
8306}
8307
Denis Vlasenko4b875702009-03-19 13:30:04 +00008308/* Reasons for skipping commands (see comment on breakcmd routine) */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008309#define SKIPBREAK (1 << 0)
8310#define SKIPCONT (1 << 1)
8311#define SKIPFUNC (1 << 2)
8312#define SKIPFILE (1 << 3)
8313#define SKIPEVAL (1 << 4)
Denis Vlasenko4b875702009-03-19 13:30:04 +00008314static smallint evalskip; /* set to SKIPxxx if we are skipping commands */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008315static int skipcount; /* number of levels to skip */
8316static int funcnest; /* depth of function calls */
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +00008317static int loopnest; /* current loop nesting level */
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008318
Denis Vlasenko4b875702009-03-19 13:30:04 +00008319/* Forward decl way out to parsing code - dotrap needs it */
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008320static int evalstring(char *s, int mask);
8321
Denis Vlasenko4b875702009-03-19 13:30:04 +00008322/* Called to execute a trap.
8323 * Single callsite - at the end of evaltree().
Denys Vlasenkob563f622010-09-25 17:15:13 +02008324 * If we return non-zero, evaltree raises EXEXIT exception.
Denis Vlasenko4b875702009-03-19 13:30:04 +00008325 *
8326 * Perhaps we should avoid entering new trap handlers
8327 * while we are executing a trap handler. [is it a TODO?]
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008328 */
8329static int
8330dotrap(void)
8331{
Denis Vlasenko4b875702009-03-19 13:30:04 +00008332 uint8_t *g;
8333 int sig;
8334 uint8_t savestatus;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008335
8336 savestatus = exitstatus;
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02008337 pending_sig = 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008338 xbarrier();
8339
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008340 TRACE(("dotrap entered\n"));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008341 for (sig = 1, g = gotsig; sig < NSIG; sig++, g++) {
8342 int want_exexit;
8343 char *t;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008344
Denis Vlasenko4b875702009-03-19 13:30:04 +00008345 if (*g == 0)
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008346 continue;
Denis Vlasenko4b875702009-03-19 13:30:04 +00008347 t = trap[sig];
8348 /* non-trapped SIGINT is handled separately by raise_interrupt,
8349 * don't upset it by resetting gotsig[SIGINT-1] */
8350 if (sig == SIGINT && !t)
8351 continue;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008352
8353 TRACE(("sig %d is active, will run handler '%s'\n", sig, t));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008354 *g = 0;
8355 if (!t)
8356 continue;
8357 want_exexit = evalstring(t, SKIPEVAL);
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008358 exitstatus = savestatus;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008359 if (want_exexit) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008360 TRACE(("dotrap returns %d\n", want_exexit));
Denis Vlasenko4b875702009-03-19 13:30:04 +00008361 return want_exexit;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008362 }
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008363 }
8364
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008365 TRACE(("dotrap returns 0\n"));
Denis Vlasenko991a1da2008-02-10 19:02:53 +00008366 return 0;
Denis Vlasenkofc06f292007-02-23 21:09:35 +00008367}
8368
Denis Vlasenkobc54cff2007-02-23 01:05:52 +00008369/* forward declarations - evaluation is fairly recursive business... */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008370static void evalloop(union node *, int);
8371static void evalfor(union node *, int);
8372static void evalcase(union node *, int);
8373static void evalsubshell(union node *, int);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008374static void expredir(union node *);
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008375static void evalpipe(union node *, int);
8376static void evalcommand(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008377static int evalbltin(const struct builtincmd *, int, char **);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008378static void prehash(union node *);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00008379
Eric Andersen62483552001-07-10 06:09:16 +00008380/*
Eric Andersenc470f442003-07-28 09:56:35 +00008381 * Evaluate a parse tree. The value is left in the global variable
8382 * exitstatus.
Eric Andersen62483552001-07-10 06:09:16 +00008383 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008384static void
Eric Andersenc470f442003-07-28 09:56:35 +00008385evaltree(union node *n, int flags)
Eric Andersen62483552001-07-10 06:09:16 +00008386{
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008387 struct jmploc *volatile savehandler = exception_handler;
8388 struct jmploc jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00008389 int checkexit = 0;
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008390 void (*evalfn)(union node *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008391 int status;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008392 int int_level;
8393
8394 SAVE_INT(int_level);
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008395
Eric Andersenc470f442003-07-28 09:56:35 +00008396 if (n == NULL) {
8397 TRACE(("evaltree(NULL) called\n"));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008398 goto out1;
Eric Andersen62483552001-07-10 06:09:16 +00008399 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008400 TRACE(("evaltree(%p: %d, %d) called\n", n, n->type, flags));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008401
8402 exception_handler = &jmploc;
8403 {
8404 int err = setjmp(jmploc.loc);
8405 if (err) {
8406 /* if it was a signal, check for trap handlers */
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008407 if (exception_type == EXSIG) {
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008408 TRACE(("exception %d (EXSIG) in evaltree, err=%d\n",
8409 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008410 goto out;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008411 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008412 /* continue on the way out */
Denis Vlasenkob21f3792009-03-19 23:09:58 +00008413 TRACE(("exception %d in evaltree, propagating err=%d\n",
8414 exception_type, err));
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008415 exception_handler = savehandler;
8416 longjmp(exception_handler->loc, err);
8417 }
8418 }
8419
Eric Andersenc470f442003-07-28 09:56:35 +00008420 switch (n->type) {
8421 default:
Denis Vlasenkoa7189f02006-11-17 20:29:00 +00008422#if DEBUG
Eric Andersenc470f442003-07-28 09:56:35 +00008423 out1fmt("Node type = %d\n", n->type);
Denys Vlasenko8131eea2009-11-02 14:19:51 +01008424 fflush_all();
Eric Andersenc470f442003-07-28 09:56:35 +00008425 break;
8426#endif
8427 case NNOT:
8428 evaltree(n->nnot.com, EV_TESTED);
8429 status = !exitstatus;
8430 goto setstatus;
8431 case NREDIR:
8432 expredir(n->nredir.redirect);
8433 status = redirectsafe(n->nredir.redirect, REDIR_PUSH);
8434 if (!status) {
8435 evaltree(n->nredir.n, flags & EV_TESTED);
8436 status = exitstatus;
8437 }
Denis Vlasenko34c73c42008-08-16 11:48:02 +00008438 popredir(/*drop:*/ 0, /*restore:*/ 0 /* not sure */);
Eric Andersenc470f442003-07-28 09:56:35 +00008439 goto setstatus;
8440 case NCMD:
8441 evalfn = evalcommand;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008442 checkexit:
Eric Andersenc470f442003-07-28 09:56:35 +00008443 if (eflag && !(flags & EV_TESTED))
8444 checkexit = ~0;
8445 goto calleval;
8446 case NFOR:
8447 evalfn = evalfor;
8448 goto calleval;
8449 case NWHILE:
8450 case NUNTIL:
8451 evalfn = evalloop;
8452 goto calleval;
8453 case NSUBSHELL:
8454 case NBACKGND:
8455 evalfn = evalsubshell;
8456 goto calleval;
8457 case NPIPE:
8458 evalfn = evalpipe;
8459 goto checkexit;
8460 case NCASE:
8461 evalfn = evalcase;
8462 goto calleval;
8463 case NAND:
8464 case NOR:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008465 case NSEMI: {
8466
Eric Andersenc470f442003-07-28 09:56:35 +00008467#if NAND + 1 != NOR
8468#error NAND + 1 != NOR
8469#endif
8470#if NOR + 1 != NSEMI
8471#error NOR + 1 != NSEMI
8472#endif
Denis Vlasenko87d5fd92008-07-26 13:48:35 +00008473 unsigned is_or = n->type - NAND;
Eric Andersenc470f442003-07-28 09:56:35 +00008474 evaltree(
8475 n->nbinary.ch1,
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008476 (flags | ((is_or >> 1) - 1)) & EV_TESTED
Eric Andersenc470f442003-07-28 09:56:35 +00008477 );
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008478 if (!exitstatus == is_or)
Eric Andersenc470f442003-07-28 09:56:35 +00008479 break;
8480 if (!evalskip) {
8481 n = n->nbinary.ch2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008482 evaln:
Eric Andersenc470f442003-07-28 09:56:35 +00008483 evalfn = evaltree;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008484 calleval:
Eric Andersenc470f442003-07-28 09:56:35 +00008485 evalfn(n, flags);
8486 break;
8487 }
8488 break;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008489 }
Eric Andersenc470f442003-07-28 09:56:35 +00008490 case NIF:
8491 evaltree(n->nif.test, EV_TESTED);
8492 if (evalskip)
8493 break;
8494 if (exitstatus == 0) {
8495 n = n->nif.ifpart;
8496 goto evaln;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008497 }
8498 if (n->nif.elsepart) {
Eric Andersenc470f442003-07-28 09:56:35 +00008499 n = n->nif.elsepart;
8500 goto evaln;
8501 }
8502 goto success;
8503 case NDEFUN:
8504 defun(n->narg.text, n->narg.next);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008505 success:
Eric Andersenc470f442003-07-28 09:56:35 +00008506 status = 0;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008507 setstatus:
Eric Andersenc470f442003-07-28 09:56:35 +00008508 exitstatus = status;
8509 break;
8510 }
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008511
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008512 out:
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008513 exception_handler = savehandler;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008514
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008515 out1:
Denys Vlasenkob563f622010-09-25 17:15:13 +02008516 /* Order of checks below is important:
8517 * signal handlers trigger before exit caused by "set -e".
8518 */
8519 if (pending_sig && dotrap())
8520 goto exexit;
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +00008521 if (checkexit & exitstatus)
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008522 evalskip |= SKIPEVAL;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008523
8524 if (flags & EV_EXIT) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008525 exexit:
Denis Vlasenkob012b102007-02-19 22:43:01 +00008526 raise_exception(EXEXIT);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00008527 }
Denis Vlasenko653d8e72009-03-19 21:59:35 +00008528
8529 RESTORE_INT(int_level);
8530 TRACE(("leaving evaltree (no interrupts)\n"));
Eric Andersen62483552001-07-10 06:09:16 +00008531}
8532
Eric Andersenc470f442003-07-28 09:56:35 +00008533#if !defined(__alpha__) || (defined(__GNUC__) && __GNUC__ >= 3)
8534static
8535#endif
8536void evaltreenr(union node *, int) __attribute__ ((alias("evaltree"),__noreturn__));
8537
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008538static void
Eric Andersenc470f442003-07-28 09:56:35 +00008539evalloop(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008540{
8541 int status;
8542
8543 loopnest++;
8544 status = 0;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008545 flags &= EV_TESTED;
Eric Andersencb57d552001-06-28 07:25:16 +00008546 for (;;) {
Eric Andersenc470f442003-07-28 09:56:35 +00008547 int i;
8548
Eric Andersencb57d552001-06-28 07:25:16 +00008549 evaltree(n->nbinary.ch1, EV_TESTED);
8550 if (evalskip) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008551 skipping:
8552 if (evalskip == SKIPCONT && --skipcount <= 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008553 evalskip = 0;
8554 continue;
8555 }
8556 if (evalskip == SKIPBREAK && --skipcount <= 0)
8557 evalskip = 0;
8558 break;
8559 }
Eric Andersenc470f442003-07-28 09:56:35 +00008560 i = exitstatus;
8561 if (n->type != NWHILE)
8562 i = !i;
8563 if (i != 0)
8564 break;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008565 evaltree(n->nbinary.ch2, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008566 status = exitstatus;
8567 if (evalskip)
8568 goto skipping;
8569 }
8570 loopnest--;
8571 exitstatus = status;
8572}
8573
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008574static void
Eric Andersenc470f442003-07-28 09:56:35 +00008575evalfor(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008576{
8577 struct arglist arglist;
8578 union node *argp;
8579 struct strlist *sp;
8580 struct stackmark smark;
8581
8582 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008583 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008584 arglist.lastp = &arglist.list;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008585 for (argp = n->nfor.args; argp; argp = argp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008586 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD);
Eric Andersenc470f442003-07-28 09:56:35 +00008587 /* XXX */
Eric Andersencb57d552001-06-28 07:25:16 +00008588 if (evalskip)
8589 goto out;
8590 }
8591 *arglist.lastp = NULL;
8592
8593 exitstatus = 0;
8594 loopnest++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008595 flags &= EV_TESTED;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008596 for (sp = arglist.list; sp; sp = sp->next) {
Bernhard Reutner-Fischer200c1c42013-11-08 14:12:13 +01008597 setvar2(n->nfor.var, sp->text);
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008598 evaltree(n->nfor.body, flags);
Eric Andersencb57d552001-06-28 07:25:16 +00008599 if (evalskip) {
8600 if (evalskip == SKIPCONT && --skipcount <= 0) {
8601 evalskip = 0;
8602 continue;
8603 }
8604 if (evalskip == SKIPBREAK && --skipcount <= 0)
8605 evalskip = 0;
8606 break;
8607 }
8608 }
8609 loopnest--;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008610 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008611 popstackmark(&smark);
8612}
8613
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008614static void
Eric Andersenc470f442003-07-28 09:56:35 +00008615evalcase(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008616{
8617 union node *cp;
8618 union node *patp;
8619 struct arglist arglist;
8620 struct stackmark smark;
8621
8622 setstackmark(&smark);
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008623 arglist.list = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +00008624 arglist.lastp = &arglist.list;
Eric Andersencb57d552001-06-28 07:25:16 +00008625 expandarg(n->ncase.expr, &arglist, EXP_TILDE);
Eric Andersenc470f442003-07-28 09:56:35 +00008626 exitstatus = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008627 for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) {
8628 for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) {
Eric Andersencb57d552001-06-28 07:25:16 +00008629 if (casematch(patp, arglist.list->text)) {
8630 if (evalskip == 0) {
8631 evaltree(cp->nclist.body, flags);
8632 }
8633 goto out;
8634 }
8635 }
8636 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008637 out:
Eric Andersencb57d552001-06-28 07:25:16 +00008638 popstackmark(&smark);
8639}
8640
Eric Andersenc470f442003-07-28 09:56:35 +00008641/*
8642 * Kick off a subshell to evaluate a tree.
8643 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008644static void
Eric Andersenc470f442003-07-28 09:56:35 +00008645evalsubshell(union node *n, int flags)
8646{
8647 struct job *jp;
8648 int backgnd = (n->type == NBACKGND);
8649 int status;
8650
8651 expredir(n->nredir.redirect);
Denys Vlasenko238bf182010-05-18 15:49:07 +02008652 if (!backgnd && (flags & EV_EXIT) && !may_have_traps)
Eric Andersenc470f442003-07-28 09:56:35 +00008653 goto nofork;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008654 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008655 jp = makejob(/*n,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008656 if (forkshell(jp, n, backgnd) == 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02008657 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00008658 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008659 flags |= EV_EXIT;
8660 if (backgnd)
Denys Vlasenko238bf182010-05-18 15:49:07 +02008661 flags &= ~EV_TESTED;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +00008662 nofork:
Eric Andersenc470f442003-07-28 09:56:35 +00008663 redirect(n->nredir.redirect, 0);
8664 evaltreenr(n->nredir.n, flags);
8665 /* never returns */
8666 }
8667 status = 0;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008668 if (!backgnd)
Eric Andersenc470f442003-07-28 09:56:35 +00008669 status = waitforjob(jp);
8670 exitstatus = status;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008671 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00008672}
8673
Eric Andersenc470f442003-07-28 09:56:35 +00008674/*
8675 * Compute the names of the files in a redirection list.
8676 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00008677static void fixredir(union node *, const char *, int);
Eric Andersenc470f442003-07-28 09:56:35 +00008678static void
8679expredir(union node *n)
8680{
8681 union node *redir;
8682
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008683 for (redir = n; redir; redir = redir->nfile.next) {
Eric Andersenc470f442003-07-28 09:56:35 +00008684 struct arglist fn;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008685
Denis Vlasenkoc12d51e2008-02-19 23:31:05 +00008686 fn.list = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +00008687 fn.lastp = &fn.list;
8688 switch (redir->type) {
8689 case NFROMTO:
8690 case NFROM:
8691 case NTO:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008692#if ENABLE_ASH_BASH_COMPAT
8693 case NTO2:
8694#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008695 case NCLOBBER:
8696 case NAPPEND:
8697 expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR);
Denys Vlasenkof451b2c2012-06-09 02:06:57 +02008698 TRACE(("expredir expanded to '%s'\n", fn.list->text));
Denis Vlasenko559691a2008-10-05 18:39:31 +00008699#if ENABLE_ASH_BASH_COMPAT
8700 store_expfname:
8701#endif
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008702#if 0
8703// By the design of stack allocator, the loop of this kind:
8704// while true; do while true; do break; done </dev/null; done
8705// will look like a memory leak: ash plans to free expfname's
8706// of "/dev/null" as soon as it finishes running the loop
8707// (in this case, never).
8708// This "fix" is wrong:
Jon Tollefson4ba6c5d2012-11-13 19:26:53 +01008709 if (redir->nfile.expfname)
8710 stunalloc(redir->nfile.expfname);
Denys Vlasenko7c4b13e2013-01-17 13:02:27 +01008711// It results in corrupted state of stacked allocations.
8712#endif
Eric Andersenc470f442003-07-28 09:56:35 +00008713 redir->nfile.expfname = fn.list->text;
8714 break;
8715 case NFROMFD:
Denis Vlasenko559691a2008-10-05 18:39:31 +00008716 case NTOFD: /* >& */
Eric Andersenc470f442003-07-28 09:56:35 +00008717 if (redir->ndup.vname) {
8718 expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE);
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008719 if (fn.list == NULL)
Denis Vlasenkob012b102007-02-19 22:43:01 +00008720 ash_msg_and_raise_error("redir error");
Denis Vlasenko559691a2008-10-05 18:39:31 +00008721#if ENABLE_ASH_BASH_COMPAT
8722//FIXME: we used expandarg with different args!
8723 if (!isdigit_str9(fn.list->text)) {
8724 /* >&file, not >&fd */
8725 if (redir->nfile.fd != 1) /* 123>&file - BAD */
8726 ash_msg_and_raise_error("redir error");
8727 redir->type = NTO2;
8728 goto store_expfname;
8729 }
8730#endif
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008731 fixredir(redir, fn.list->text, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00008732 }
8733 break;
8734 }
8735 }
8736}
8737
Eric Andersencb57d552001-06-28 07:25:16 +00008738/*
Eric Andersencb57d552001-06-28 07:25:16 +00008739 * Evaluate a pipeline. All the processes in the pipeline are children
8740 * of the process creating the pipeline. (This differs from some versions
8741 * of the shell, which make the last process in a pipeline the parent
8742 * of all the rest.)
8743 */
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02008744static void
Eric Andersenc470f442003-07-28 09:56:35 +00008745evalpipe(union node *n, int flags)
Eric Andersencb57d552001-06-28 07:25:16 +00008746{
8747 struct job *jp;
8748 struct nodelist *lp;
8749 int pipelen;
8750 int prevfd;
8751 int pip[2];
8752
Eric Andersenc470f442003-07-28 09:56:35 +00008753 TRACE(("evalpipe(0x%lx) called\n", (long)n));
Eric Andersencb57d552001-06-28 07:25:16 +00008754 pipelen = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008755 for (lp = n->npipe.cmdlist; lp; lp = lp->next)
Eric Andersencb57d552001-06-28 07:25:16 +00008756 pipelen++;
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008757 flags |= EV_EXIT;
Denis Vlasenkob012b102007-02-19 22:43:01 +00008758 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00008759 jp = makejob(/*n,*/ pipelen);
Eric Andersencb57d552001-06-28 07:25:16 +00008760 prevfd = -1;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00008761 for (lp = n->npipe.cmdlist; lp; lp = lp->next) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008762 prehash(lp->n);
Eric Andersencb57d552001-06-28 07:25:16 +00008763 pip[1] = -1;
8764 if (lp->next) {
8765 if (pipe(pip) < 0) {
8766 close(prevfd);
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +00008767 ash_msg_and_raise_error("pipe call failed");
Eric Andersencb57d552001-06-28 07:25:16 +00008768 }
8769 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008770 if (forkshell(jp, lp->n, n->npipe.pipe_backgnd) == 0) {
Denis Vlasenkob012b102007-02-19 22:43:01 +00008771 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008772 if (pip[1] >= 0) {
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008773 close(pip[0]);
Eric Andersencb57d552001-06-28 07:25:16 +00008774 }
Glenn L McGrath50812ff2002-08-23 13:14:48 +00008775 if (prevfd > 0) {
8776 dup2(prevfd, 0);
8777 close(prevfd);
8778 }
8779 if (pip[1] > 1) {
8780 dup2(pip[1], 1);
8781 close(pip[1]);
8782 }
Eric Andersenc470f442003-07-28 09:56:35 +00008783 evaltreenr(lp->n, flags);
8784 /* never returns */
Eric Andersencb57d552001-06-28 07:25:16 +00008785 }
8786 if (prevfd >= 0)
8787 close(prevfd);
8788 prevfd = pip[0];
Denis Vlasenkob9e70dd2009-03-20 01:24:08 +00008789 /* Don't want to trigger debugging */
8790 if (pip[1] != -1)
8791 close(pip[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00008792 }
Denis Vlasenko2dc240c2008-07-24 06:07:50 +00008793 if (n->npipe.pipe_backgnd == 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00008794 exitstatus = waitforjob(jp);
8795 TRACE(("evalpipe: job done exit status %d\n", exitstatus));
Eric Andersencb57d552001-06-28 07:25:16 +00008796 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00008797 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +00008798}
8799
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008800/*
8801 * Controls whether the shell is interactive or not.
8802 */
8803static void
8804setinteractive(int on)
8805{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008806 static smallint is_interactive;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008807
8808 if (++on == is_interactive)
8809 return;
8810 is_interactive = on;
8811 setsignal(SIGINT);
8812 setsignal(SIGQUIT);
8813 setsignal(SIGTERM);
8814#if !ENABLE_FEATURE_SH_EXTRA_QUIET
8815 if (is_interactive > 1) {
8816 /* Looks like they want an interactive shell */
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008817 static smallint did_banner;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008818
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008819 if (!did_banner) {
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008820 /* note: ash and hush share this string */
8821 out1fmt("\n\n%s %s\n"
Denys Vlasenko2ec34962014-09-08 16:52:39 +02008822 IF_ASH_HELP("Enter 'help' for a list of built-in commands.\n")
8823 "\n",
Denys Vlasenkoc34c0332009-09-29 12:25:30 +02008824 bb_banner,
8825 "built-in shell (ash)"
8826 );
Denis Vlasenkoca525b42007-06-13 12:27:17 +00008827 did_banner = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008828 }
8829 }
8830#endif
8831}
8832
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008833static void
8834optschanged(void)
8835{
8836#if DEBUG
8837 opentrace();
8838#endif
8839 setinteractive(iflag);
8840 setjobctl(mflag);
Denis Vlasenkob07a4962008-06-22 13:16:23 +00008841#if ENABLE_FEATURE_EDITING_VI
8842 if (viflag)
8843 line_input_state->flags |= VI_MODE;
8844 else
8845 line_input_state->flags &= ~VI_MODE;
8846#else
8847 viflag = 0; /* forcibly keep the option off */
8848#endif
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00008849}
8850
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008851static struct localvar *localvars;
8852
8853/*
8854 * Called after a function returns.
8855 * Interrupts must be off.
8856 */
8857static void
8858poplocalvars(void)
8859{
8860 struct localvar *lvp;
8861 struct var *vp;
8862
8863 while ((lvp = localvars) != NULL) {
8864 localvars = lvp->next;
8865 vp = lvp->vp;
Denys Vlasenkob563f622010-09-25 17:15:13 +02008866 TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-"));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008867 if (vp == NULL) { /* $- saved */
8868 memcpy(optlist, lvp->text, sizeof(optlist));
8869 free((char*)lvp->text);
8870 optschanged();
8871 } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008872 unsetvar(vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008873 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008874 if (vp->var_func)
8875 vp->var_func(var_end(lvp->text));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008876 if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008877 free((char*)vp->var_text);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008878 vp->flags = lvp->flags;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008879 vp->var_text = lvp->text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008880 }
8881 free(lvp);
8882 }
8883}
8884
8885static int
8886evalfun(struct funcnode *func, int argc, char **argv, int flags)
8887{
8888 volatile struct shparam saveparam;
8889 struct localvar *volatile savelocalvars;
8890 struct jmploc *volatile savehandler;
8891 struct jmploc jmploc;
8892 int e;
8893
8894 saveparam = shellparam;
8895 savelocalvars = localvars;
8896 e = setjmp(jmploc.loc);
8897 if (e) {
8898 goto funcdone;
8899 }
8900 INT_OFF;
8901 savehandler = exception_handler;
8902 exception_handler = &jmploc;
8903 localvars = NULL;
Denis Vlasenko01631112007-12-16 17:20:38 +00008904 shellparam.malloced = 0;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008905 func->count++;
8906 funcnest++;
8907 INT_ON;
8908 shellparam.nparam = argc - 1;
8909 shellparam.p = argv + 1;
8910#if ENABLE_ASH_GETOPTS
8911 shellparam.optind = 1;
8912 shellparam.optoff = -1;
8913#endif
8914 evaltree(&func->n, flags & EV_TESTED);
Denis Vlasenko01631112007-12-16 17:20:38 +00008915 funcdone:
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008916 INT_OFF;
8917 funcnest--;
8918 freefunc(func);
8919 poplocalvars();
8920 localvars = savelocalvars;
8921 freeparam(&shellparam);
8922 shellparam = saveparam;
8923 exception_handler = savehandler;
8924 INT_ON;
8925 evalskip &= ~SKIPFUNC;
8926 return e;
8927}
8928
Denis Vlasenko131ae172007-02-18 13:00:19 +00008929#if ENABLE_ASH_CMDCMD
Denis Vlasenkoaa744452007-02-23 01:04:22 +00008930static char **
8931parse_command_args(char **argv, const char **path)
Eric Andersenc470f442003-07-28 09:56:35 +00008932{
8933 char *cp, c;
8934
8935 for (;;) {
8936 cp = *++argv;
8937 if (!cp)
8938 return 0;
8939 if (*cp++ != '-')
8940 break;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00008941 c = *cp++;
8942 if (!c)
Eric Andersenc470f442003-07-28 09:56:35 +00008943 break;
8944 if (c == '-' && !*cp) {
8945 argv++;
8946 break;
8947 }
8948 do {
8949 switch (c) {
8950 case 'p':
Denis Vlasenkof5f75c52007-06-12 22:35:19 +00008951 *path = bb_default_path;
Eric Andersenc470f442003-07-28 09:56:35 +00008952 break;
8953 default:
8954 /* run 'typecmd' for other options */
8955 return 0;
8956 }
Denis Vlasenko9650f362007-02-23 01:04:37 +00008957 c = *cp++;
8958 } while (c);
Eric Andersenc470f442003-07-28 09:56:35 +00008959 }
8960 return argv;
8961}
8962#endif
8963
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008964/*
8965 * Make a variable a local variable. When a variable is made local, it's
8966 * value and flags are saved in a localvar structure. The saved values
8967 * will be restored when the shell function returns. We handle the name
8968 * "-" as a special case.
8969 */
8970static void
8971mklocal(char *name)
8972{
8973 struct localvar *lvp;
8974 struct var **vpp;
8975 struct var *vp;
8976
8977 INT_OFF;
Denis Vlasenko838ffd52008-02-21 04:32:08 +00008978 lvp = ckzalloc(sizeof(struct localvar));
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008979 if (LONE_DASH(name)) {
8980 char *p;
8981 p = ckmalloc(sizeof(optlist));
8982 lvp->text = memcpy(p, optlist, sizeof(optlist));
8983 vp = NULL;
8984 } else {
8985 char *eq;
8986
8987 vpp = hashvar(name);
8988 vp = *findvar(vpp, name);
8989 eq = strchr(name, '=');
8990 if (vp == NULL) {
8991 if (eq)
8992 setvareq(name, VSTRFIXED);
8993 else
8994 setvar(name, NULL, VSTRFIXED);
8995 vp = *vpp; /* the new variable */
8996 lvp->flags = VUNSET;
8997 } else {
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02008998 lvp->text = vp->var_text;
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00008999 lvp->flags = vp->flags;
9000 vp->flags |= VSTRFIXED|VTEXTFIXED;
9001 if (eq)
9002 setvareq(name, 0);
Denys Vlasenko109ee5d2014-03-16 18:41:11 +01009003 else
9004 /* "local VAR" unsets VAR: */
9005 setvar(name, NULL, 0);
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009006 }
9007 }
9008 lvp->vp = vp;
9009 lvp->next = localvars;
9010 localvars = lvp;
9011 INT_ON;
9012}
9013
9014/*
9015 * The "local" command.
9016 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009017static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009018localcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009019{
9020 char *name;
9021
9022 argv = argptr;
9023 while ((name = *argv++) != NULL) {
9024 mklocal(name);
9025 }
9026 return 0;
9027}
9028
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009029static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009030falsecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009031{
9032 return 1;
9033}
9034
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009035static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009036truecmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009037{
9038 return 0;
9039}
9040
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009041static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009042execcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009043{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009044 if (argv[1]) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009045 iflag = 0; /* exit on error */
9046 mflag = 0;
9047 optschanged();
9048 shellexec(argv + 1, pathval(), 0);
9049 }
9050 return 0;
9051}
9052
9053/*
9054 * The return command.
9055 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009056static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009057returncmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009058{
9059 /*
9060 * If called outside a function, do what ksh does;
9061 * skip the rest of the file.
9062 */
9063 evalskip = funcnest ? SKIPFUNC : SKIPFILE;
9064 return argv[1] ? number(argv[1]) : exitstatus;
9065}
9066
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009067/* Forward declarations for builtintab[] */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009068static int breakcmd(int, char **) FAST_FUNC;
9069static int dotcmd(int, char **) FAST_FUNC;
9070static int evalcmd(int, char **) FAST_FUNC;
9071static int exitcmd(int, char **) FAST_FUNC;
9072static int exportcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009073#if ENABLE_ASH_GETOPTS
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009074static int getoptscmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009075#endif
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009076#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009077static int helpcmd(int, char **) FAST_FUNC;
Denis Vlasenko52764022007-02-24 13:42:56 +00009078#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009079#if MAX_HISTORY
9080static int historycmd(int, char **) FAST_FUNC;
9081#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009082#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009083static int letcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009084#endif
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009085static int readcmd(int, char **) FAST_FUNC;
9086static int setcmd(int, char **) FAST_FUNC;
9087static int shiftcmd(int, char **) FAST_FUNC;
9088static int timescmd(int, char **) FAST_FUNC;
9089static int trapcmd(int, char **) FAST_FUNC;
9090static int umaskcmd(int, char **) FAST_FUNC;
9091static int unsetcmd(int, char **) FAST_FUNC;
9092static int ulimitcmd(int, char **) FAST_FUNC;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009093
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009094#define BUILTIN_NOSPEC "0"
9095#define BUILTIN_SPECIAL "1"
9096#define BUILTIN_REGULAR "2"
9097#define BUILTIN_SPEC_REG "3"
9098#define BUILTIN_ASSIGN "4"
9099#define BUILTIN_SPEC_ASSG "5"
9100#define BUILTIN_REG_ASSG "6"
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009101#define BUILTIN_SPEC_REG_ASSG "7"
9102
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009103/* Stubs for calling non-FAST_FUNC's */
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009104#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009105static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009106#endif
9107#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009108static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009109#endif
9110#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009111static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
Denys Vlasenko2634bf32009-06-09 18:40:07 +02009112#endif
Denis Vlasenko468aea22008-04-01 14:47:57 +00009113
Denis Vlasenkof7d56652008-03-25 05:51:41 +00009114/* Keep these in proper order since it is searched via bsearch() */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009115static const struct builtincmd builtintab[] = {
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009116 { BUILTIN_SPEC_REG "." , dotcmd },
9117 { BUILTIN_SPEC_REG ":" , truecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009118#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009119 { BUILTIN_REGULAR "[" , testcmd },
Denis Vlasenko80591b02008-03-25 07:49:43 +00009120#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009121 { BUILTIN_REGULAR "[[" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009122#endif
Denis Vlasenko80591b02008-03-25 07:49:43 +00009123#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009124#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009125 { BUILTIN_REG_ASSG "alias" , aliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009126#endif
9127#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009128 { BUILTIN_REGULAR "bg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009129#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009130 { BUILTIN_SPEC_REG "break" , breakcmd },
9131 { BUILTIN_REGULAR "cd" , cdcmd },
9132 { BUILTIN_NOSPEC "chdir" , cdcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009133#if ENABLE_ASH_CMDCMD
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009134 { BUILTIN_REGULAR "command" , commandcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009135#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009136 { BUILTIN_SPEC_REG "continue", breakcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009137#if ENABLE_ASH_BUILTIN_ECHO
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009138 { BUILTIN_REGULAR "echo" , echocmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009139#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009140 { BUILTIN_SPEC_REG "eval" , evalcmd },
9141 { BUILTIN_SPEC_REG "exec" , execcmd },
9142 { BUILTIN_SPEC_REG "exit" , exitcmd },
9143 { BUILTIN_SPEC_REG_ASSG "export" , exportcmd },
9144 { BUILTIN_REGULAR "false" , falsecmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009145#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009146 { BUILTIN_REGULAR "fg" , fg_bgcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009147#endif
9148#if ENABLE_ASH_GETOPTS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009149 { BUILTIN_REGULAR "getopts" , getoptscmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009150#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009151 { BUILTIN_NOSPEC "hash" , hashcmd },
Denys Vlasenko2ec34962014-09-08 16:52:39 +02009152#if ENABLE_ASH_HELP
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009153 { BUILTIN_NOSPEC "help" , helpcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009154#endif
Flemming Madsend96ffda2013-04-07 18:47:24 +02009155#if MAX_HISTORY
9156 { BUILTIN_NOSPEC "history" , historycmd },
9157#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009158#if JOBS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009159 { BUILTIN_REGULAR "jobs" , jobscmd },
9160 { BUILTIN_REGULAR "kill" , killcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009161#endif
Mike Frysinger98c52642009-04-02 10:02:37 +00009162#if ENABLE_SH_MATH_SUPPORT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009163 { BUILTIN_NOSPEC "let" , letcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009164#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009165 { BUILTIN_ASSIGN "local" , localcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009166#if ENABLE_ASH_BUILTIN_PRINTF
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009167 { BUILTIN_REGULAR "printf" , printfcmd },
Denis Vlasenkocd2663f2008-06-01 22:36:39 +00009168#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009169 { BUILTIN_NOSPEC "pwd" , pwdcmd },
9170 { BUILTIN_REGULAR "read" , readcmd },
9171 { BUILTIN_SPEC_REG_ASSG "readonly", exportcmd },
9172 { BUILTIN_SPEC_REG "return" , returncmd },
9173 { BUILTIN_SPEC_REG "set" , setcmd },
9174 { BUILTIN_SPEC_REG "shift" , shiftcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009175#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009176 { BUILTIN_SPEC_REG "source" , dotcmd },
Denys Vlasenko82731b42010-05-17 17:49:52 +02009177#endif
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009178#if ENABLE_ASH_BUILTIN_TEST
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009179 { BUILTIN_REGULAR "test" , testcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009180#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009181 { BUILTIN_SPEC_REG "times" , timescmd },
9182 { BUILTIN_SPEC_REG "trap" , trapcmd },
9183 { BUILTIN_REGULAR "true" , truecmd },
9184 { BUILTIN_NOSPEC "type" , typecmd },
9185 { BUILTIN_NOSPEC "ulimit" , ulimitcmd },
9186 { BUILTIN_REGULAR "umask" , umaskcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009187#if ENABLE_ASH_ALIAS
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009188 { BUILTIN_REGULAR "unalias" , unaliascmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009189#endif
Denys Vlasenko023a08f2010-03-26 15:53:33 +01009190 { BUILTIN_SPEC_REG "unset" , unsetcmd },
9191 { BUILTIN_REGULAR "wait" , waitcmd },
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009192};
9193
Denis Vlasenko80591b02008-03-25 07:49:43 +00009194/* Should match the above table! */
9195#define COMMANDCMD (builtintab + \
9196 2 + \
9197 1 * ENABLE_ASH_BUILTIN_TEST + \
9198 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9199 1 * ENABLE_ASH_ALIAS + \
9200 1 * ENABLE_ASH_JOB_CONTROL + \
9201 3)
9202#define EXECCMD (builtintab + \
9203 2 + \
9204 1 * ENABLE_ASH_BUILTIN_TEST + \
9205 1 * ENABLE_ASH_BUILTIN_TEST * ENABLE_ASH_BASH_COMPAT + \
9206 1 * ENABLE_ASH_ALIAS + \
9207 1 * ENABLE_ASH_JOB_CONTROL + \
9208 3 + \
9209 1 * ENABLE_ASH_CMDCMD + \
9210 1 + \
9211 ENABLE_ASH_BUILTIN_ECHO + \
9212 1)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009213
9214/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009215 * Search the table of builtin commands.
9216 */
9217static struct builtincmd *
9218find_builtin(const char *name)
9219{
9220 struct builtincmd *bp;
9221
9222 bp = bsearch(
Denis Vlasenko80b8b392007-06-25 10:55:35 +00009223 name, builtintab, ARRAY_SIZE(builtintab), sizeof(builtintab[0]),
Denis Vlasenko5651bfc2007-02-23 21:08:58 +00009224 pstrcmp
9225 );
9226 return bp;
9227}
9228
9229/*
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009230 * Execute a simple command.
9231 */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009232static int
9233isassignment(const char *p)
Paul Foxc3850c82005-07-20 18:23:39 +00009234{
9235 const char *q = endofname(p);
9236 if (p == q)
9237 return 0;
9238 return *q == '=';
9239}
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009240static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009241bltincmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009242{
9243 /* Preserve exitstatus of a previous possible redirection
9244 * as POSIX mandates */
9245 return back_exitstatus;
9246}
Denys Vlasenko641dd7b2009-06-11 19:30:19 +02009247static void
Eric Andersenc470f442003-07-28 09:56:35 +00009248evalcommand(union node *cmd, int flags)
9249{
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009250 static const struct builtincmd null_bltin = {
9251 "\0\0", bltincmd /* why three NULs? */
Denis Vlasenko4fe15f32007-02-23 01:05:26 +00009252 };
Eric Andersenc470f442003-07-28 09:56:35 +00009253 struct stackmark smark;
9254 union node *argp;
9255 struct arglist arglist;
9256 struct arglist varlist;
9257 char **argv;
9258 int argc;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009259 const struct strlist *sp;
Eric Andersenc470f442003-07-28 09:56:35 +00009260 struct cmdentry cmdentry;
9261 struct job *jp;
9262 char *lastarg;
9263 const char *path;
9264 int spclbltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009265 int status;
9266 char **nargv;
Paul Foxc3850c82005-07-20 18:23:39 +00009267 struct builtincmd *bcmd;
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009268 smallint cmd_is_exec;
9269 smallint pseudovarflag = 0;
Eric Andersenc470f442003-07-28 09:56:35 +00009270
9271 /* First expand the arguments. */
9272 TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags));
9273 setstackmark(&smark);
9274 back_exitstatus = 0;
9275
9276 cmdentry.cmdtype = CMDBUILTIN;
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009277 cmdentry.u.cmd = &null_bltin;
Eric Andersenc470f442003-07-28 09:56:35 +00009278 varlist.lastp = &varlist.list;
9279 *varlist.lastp = NULL;
9280 arglist.lastp = &arglist.list;
9281 *arglist.lastp = NULL;
9282
9283 argc = 0;
Denis Vlasenkob012b102007-02-19 22:43:01 +00009284 if (cmd->ncmd.args) {
Paul Foxc3850c82005-07-20 18:23:39 +00009285 bcmd = find_builtin(cmd->ncmd.args->narg.text);
9286 pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd);
9287 }
9288
Eric Andersenc470f442003-07-28 09:56:35 +00009289 for (argp = cmd->ncmd.args; argp; argp = argp->narg.next) {
9290 struct strlist **spp;
9291
9292 spp = arglist.lastp;
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +00009293 if (pseudovarflag && isassignment(argp->narg.text))
Paul Foxc3850c82005-07-20 18:23:39 +00009294 expandarg(argp, &arglist, EXP_VARTILDE);
9295 else
9296 expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
9297
Eric Andersenc470f442003-07-28 09:56:35 +00009298 for (sp = *spp; sp; sp = sp->next)
9299 argc++;
9300 }
9301
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009302 argv = nargv = stalloc(sizeof(char *) * (argc + 1));
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009303 for (sp = arglist.list; sp; sp = sp->next) {
Eric Andersenc470f442003-07-28 09:56:35 +00009304 TRACE(("evalcommand arg: %s\n", sp->text));
9305 *nargv++ = sp->text;
9306 }
9307 *nargv = NULL;
9308
9309 lastarg = NULL;
9310 if (iflag && funcnest == 0 && argc > 0)
9311 lastarg = nargv[-1];
9312
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009313 preverrout_fd = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009314 expredir(cmd->ncmd.redirect);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +00009315 status = redirectsafe(cmd->ncmd.redirect, REDIR_PUSH | REDIR_SAVEFD2);
Eric Andersenc470f442003-07-28 09:56:35 +00009316
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009317 path = vpath.var_text;
Eric Andersenc470f442003-07-28 09:56:35 +00009318 for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) {
9319 struct strlist **spp;
9320 char *p;
9321
9322 spp = varlist.lastp;
9323 expandarg(argp, &varlist, EXP_VARTILDE);
9324
9325 /*
9326 * Modify the command lookup path, if a PATH= assignment
9327 * is present
9328 */
9329 p = (*spp)->text;
Denys Vlasenko8837c5d2010-06-02 12:56:18 +02009330 if (varcmp(p, path) == 0)
Eric Andersenc470f442003-07-28 09:56:35 +00009331 path = p;
9332 }
9333
9334 /* Print the command if xflag is set. */
9335 if (xflag) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009336 int n;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009337 const char *p = " %s" + 1;
Eric Andersenc470f442003-07-28 09:56:35 +00009338
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009339 fdprintf(preverrout_fd, p, expandstr(ps4val()));
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009340 sp = varlist.list;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009341 for (n = 0; n < 2; n++) {
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009342 while (sp) {
Denis Vlasenko0de37e12007-10-17 11:08:53 +00009343 fdprintf(preverrout_fd, p, sp->text);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009344 sp = sp->next;
Denys Vlasenkofd33e172010-06-26 22:55:44 +02009345 p = " %s";
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009346 }
9347 sp = arglist.list;
9348 }
Denis Vlasenko0e6f6612008-02-15 15:02:15 +00009349 safe_write(preverrout_fd, "\n", 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009350 }
9351
9352 cmd_is_exec = 0;
9353 spclbltin = -1;
9354
9355 /* Now locate the command. */
9356 if (argc) {
Eric Andersenc470f442003-07-28 09:56:35 +00009357 int cmd_flag = DO_ERR;
Denys Vlasenko0b4980c2012-09-25 12:49:29 +02009358#if ENABLE_ASH_CMDCMD
9359 const char *oldpath = path + 5;
9360#endif
Eric Andersenc470f442003-07-28 09:56:35 +00009361 path += 5;
Eric Andersenc470f442003-07-28 09:56:35 +00009362 for (;;) {
9363 find_command(argv[0], &cmdentry, cmd_flag, path);
9364 if (cmdentry.cmdtype == CMDUNKNOWN) {
Denys Vlasenko8131eea2009-11-02 14:19:51 +01009365 flush_stdout_stderr();
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009366 status = 127;
Eric Andersenc470f442003-07-28 09:56:35 +00009367 goto bail;
9368 }
9369
9370 /* implement bltin and command here */
9371 if (cmdentry.cmdtype != CMDBUILTIN)
9372 break;
9373 if (spclbltin < 0)
9374 spclbltin = IS_BUILTIN_SPECIAL(cmdentry.u.cmd);
9375 if (cmdentry.u.cmd == EXECCMD)
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009376 cmd_is_exec = 1;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009377#if ENABLE_ASH_CMDCMD
Eric Andersenc470f442003-07-28 09:56:35 +00009378 if (cmdentry.u.cmd == COMMANDCMD) {
Eric Andersenc470f442003-07-28 09:56:35 +00009379 path = oldpath;
9380 nargv = parse_command_args(argv, &path);
9381 if (!nargv)
9382 break;
9383 argc -= nargv - argv;
9384 argv = nargv;
9385 cmd_flag |= DO_NOFUNC;
9386 } else
9387#endif
9388 break;
9389 }
9390 }
9391
9392 if (status) {
9393 /* We have a redirection error. */
9394 if (spclbltin > 0)
Denis Vlasenkob012b102007-02-19 22:43:01 +00009395 raise_exception(EXERROR);
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009396 bail:
Eric Andersenc470f442003-07-28 09:56:35 +00009397 exitstatus = status;
9398 goto out;
9399 }
9400
9401 /* Execute the command. */
9402 switch (cmdentry.cmdtype) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009403 default: {
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009404
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009405#if ENABLE_FEATURE_SH_NOFORK
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009406/* (1) BUG: if variables are set, we need to fork, or save/restore them
9407 * around run_nofork_applet() call.
9408 * (2) Should this check also be done in forkshell()?
9409 * (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
9410 */
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009411 /* find_command() encodes applet_no as (-2 - applet_no) */
9412 int applet_no = (- cmdentry.u.index - 2);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009413 if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009414 listsetvar(varlist.list, VEXPORT|VSTACK);
Denis Vlasenko7465dbc2008-04-13 02:25:53 +00009415 /* run <applet>_main() */
9416 exitstatus = run_nofork_applet(applet_no, argv);
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009417 break;
9418 }
Denis Vlasenko9bc80d72008-04-12 20:07:53 +00009419#endif
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009420 /* Can we avoid forking off? For example, very last command
9421 * in a script or a subshell does not need forking,
9422 * we can just exec it.
9423 */
Denys Vlasenko238bf182010-05-18 15:49:07 +02009424 if (!(flags & EV_EXIT) || may_have_traps) {
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009425 /* No, forking off a child is necessary */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009426 INT_OFF;
Denis Vlasenko68404f12008-03-17 09:00:54 +00009427 jp = makejob(/*cmd,*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009428 if (forkshell(jp, cmd, FORK_FG) != 0) {
Denys Vlasenko238bf182010-05-18 15:49:07 +02009429 /* parent */
Eric Andersenc470f442003-07-28 09:56:35 +00009430 exitstatus = waitforjob(jp);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009431 INT_ON;
Denis Vlasenko653d8e72009-03-19 21:59:35 +00009432 TRACE(("forked child exited with %d\n", exitstatus));
Eric Andersenc470f442003-07-28 09:56:35 +00009433 break;
9434 }
Denys Vlasenko238bf182010-05-18 15:49:07 +02009435 /* child */
Denis Vlasenkob012b102007-02-19 22:43:01 +00009436 FORCE_INT_ON;
Denys Vlasenkoc7f95d22010-05-18 15:52:23 +02009437 /* fall through to exec'ing external program */
Eric Andersenc470f442003-07-28 09:56:35 +00009438 }
9439 listsetvar(varlist.list, VEXPORT|VSTACK);
9440 shellexec(argv, path, cmdentry.u.index);
9441 /* NOTREACHED */
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009442 } /* default */
Eric Andersenc470f442003-07-28 09:56:35 +00009443 case CMDBUILTIN:
9444 cmdenviron = varlist.list;
9445 if (cmdenviron) {
9446 struct strlist *list = cmdenviron;
9447 int i = VNOSET;
9448 if (spclbltin > 0 || argc == 0) {
9449 i = 0;
9450 if (cmd_is_exec && argc > 1)
9451 i = VEXPORT;
9452 }
9453 listsetvar(list, i);
9454 }
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009455 /* Tight loop with builtins only:
9456 * "while kill -0 $child; do true; done"
9457 * will never exit even if $child died, unless we do this
9458 * to reap the zombie and make kill detect that it's gone: */
9459 dowait(DOWAIT_NONBLOCK, NULL);
9460
Eric Andersenc470f442003-07-28 09:56:35 +00009461 if (evalbltin(cmdentry.u.cmd, argc, argv)) {
9462 int exit_status;
Denis Vlasenko7f88e342009-03-19 03:36:18 +00009463 int i = exception_type;
Eric Andersenc470f442003-07-28 09:56:35 +00009464 if (i == EXEXIT)
9465 goto raise;
Eric Andersenc470f442003-07-28 09:56:35 +00009466 exit_status = 2;
Eric Andersenc470f442003-07-28 09:56:35 +00009467 if (i == EXINT)
Denis Vlasenko991a1da2008-02-10 19:02:53 +00009468 exit_status = 128 + SIGINT;
Eric Andersenc470f442003-07-28 09:56:35 +00009469 if (i == EXSIG)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009470 exit_status = 128 + pending_sig;
Eric Andersenc470f442003-07-28 09:56:35 +00009471 exitstatus = exit_status;
Eric Andersenc470f442003-07-28 09:56:35 +00009472 if (i == EXINT || spclbltin > 0) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009473 raise:
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009474 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009475 }
Denis Vlasenkob012b102007-02-19 22:43:01 +00009476 FORCE_INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009477 }
9478 break;
9479
9480 case CMDFUNCTION:
9481 listsetvar(varlist.list, 0);
Denis Vlasenkobe54d6b2008-10-27 14:25:52 +00009482 /* See above for the rationale */
9483 dowait(DOWAIT_NONBLOCK, NULL);
Eric Andersenc470f442003-07-28 09:56:35 +00009484 if (evalfun(cmdentry.u.func, argc, argv, flags))
9485 goto raise;
9486 break;
Denys Vlasenko42c4b2e2010-05-18 16:13:56 +02009487
9488 } /* switch */
Eric Andersenc470f442003-07-28 09:56:35 +00009489
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009490 out:
Denis Vlasenko34c73c42008-08-16 11:48:02 +00009491 popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009492 if (lastarg) {
Eric Andersenc470f442003-07-28 09:56:35 +00009493 /* dsl: I think this is intended to be used to support
9494 * '_' in 'vi' command mode during line editing...
9495 * However I implemented that within libedit itself.
9496 */
Bernhard Reutner-Fischer200c1c42013-11-08 14:12:13 +01009497 setvar2("_", lastarg);
Denis Vlasenko6514c5e2008-07-24 13:41:37 +00009498 }
Eric Andersenc470f442003-07-28 09:56:35 +00009499 popstackmark(&smark);
9500}
9501
9502static int
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009503evalbltin(const struct builtincmd *cmd, int argc, char **argv)
9504{
Eric Andersenc470f442003-07-28 09:56:35 +00009505 char *volatile savecmdname;
9506 struct jmploc *volatile savehandler;
9507 struct jmploc jmploc;
9508 int i;
9509
9510 savecmdname = commandname;
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009511 i = setjmp(jmploc.loc);
9512 if (i)
Eric Andersenc470f442003-07-28 09:56:35 +00009513 goto cmddone;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009514 savehandler = exception_handler;
9515 exception_handler = &jmploc;
Eric Andersenc470f442003-07-28 09:56:35 +00009516 commandname = argv[0];
9517 argptr = argv + 1;
9518 optptr = NULL; /* initialize nextopt */
9519 exitstatus = (*cmd->builtin)(argc, argv);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009520 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009521 cmddone:
Glenn L McGrath7b8765c2003-08-29 07:29:30 +00009522 exitstatus |= ferror(stdout);
Rob Landleyf296f0b2006-07-06 01:09:21 +00009523 clearerr(stdout);
Eric Andersenc470f442003-07-28 09:56:35 +00009524 commandname = savecmdname;
Denis Vlasenko2da584f2007-02-19 22:44:05 +00009525 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +00009526
9527 return i;
9528}
9529
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009530static int
9531goodname(const char *p)
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009532{
Denys Vlasenko8b2f13d2010-09-07 12:19:33 +02009533 return endofname(p)[0] == '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009534}
9535
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009536
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009537/*
9538 * Search for a command. This is called before we fork so that the
9539 * location of the command will be available in the parent as well as
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009540 * the child. The check for "goodname" is an overly conservative
9541 * check that the name will not be subject to expansion.
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009542 */
Eric Andersenc470f442003-07-28 09:56:35 +00009543static void
9544prehash(union node *n)
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009545{
9546 struct cmdentry entry;
9547
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +00009548 if (n->type == NCMD && n->ncmd.args && goodname(n->ncmd.args->narg.text))
9549 find_command(n->ncmd.args->narg.text, &entry, 0, pathval());
Glenn L McGrath50812ff2002-08-23 13:14:48 +00009550}
9551
Eric Andersencb57d552001-06-28 07:25:16 +00009552
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009553/* ============ Builtin commands
9554 *
9555 * Builtin commands whose functions are closely tied to evaluation
9556 * are implemented here.
Eric Andersencb57d552001-06-28 07:25:16 +00009557 */
9558
9559/*
Eric Andersencb57d552001-06-28 07:25:16 +00009560 * Handle break and continue commands. Break, continue, and return are
9561 * all handled by setting the evalskip flag. The evaluation routines
9562 * above all check this flag, and if it is set they start skipping
9563 * commands rather than executing them. The variable skipcount is
9564 * the number of loops to break/continue, or the number of function
9565 * levels to return. (The latter is always 1.) It should probably
9566 * be an error to break out of more loops than exist, but it isn't
9567 * in the standard shell so we don't make it one here.
9568 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +02009569static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00009570breakcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +00009571{
Denis Vlasenko68404f12008-03-17 09:00:54 +00009572 int n = argv[1] ? number(argv[1]) : 1;
Eric Andersencb57d552001-06-28 07:25:16 +00009573
Aaron Lehmann2aef3a62001-12-31 06:03:12 +00009574 if (n <= 0)
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +02009575 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersencb57d552001-06-28 07:25:16 +00009576 if (n > loopnest)
9577 n = loopnest;
9578 if (n > 0) {
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +00009579 evalskip = (**argv == 'c') ? SKIPCONT : SKIPBREAK;
Eric Andersencb57d552001-06-28 07:25:16 +00009580 skipcount = n;
9581 }
9582 return 0;
9583}
9584
Eric Andersenc470f442003-07-28 09:56:35 +00009585
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009586/* ============ input.c
9587 *
Eric Andersen90898442003-08-06 11:20:52 +00009588 * This implements the input routines used by the parser.
Eric Andersencb57d552001-06-28 07:25:16 +00009589 */
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009590
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009591enum {
9592 INPUT_PUSH_FILE = 1,
9593 INPUT_NOFILE_OK = 2,
9594};
Eric Andersencb57d552001-06-28 07:25:16 +00009595
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009596static smallint checkkwd;
Denis Vlasenko99eb8502007-02-23 21:09:49 +00009597/* values of checkkwd variable */
9598#define CHKALIAS 0x1
9599#define CHKKWD 0x2
9600#define CHKNL 0x4
9601
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009602/*
9603 * Push a string back onto the input at this current parsefile level.
9604 * We handle aliases this way.
9605 */
9606#if !ENABLE_ASH_ALIAS
9607#define pushstring(s, ap) pushstring(s)
9608#endif
9609static void
9610pushstring(char *s, struct alias *ap)
9611{
9612 struct strpush *sp;
9613 int len;
9614
9615 len = strlen(s);
9616 INT_OFF;
9617 if (g_parsefile->strpush) {
9618 sp = ckzalloc(sizeof(*sp));
9619 sp->prev = g_parsefile->strpush;
9620 } else {
9621 sp = &(g_parsefile->basestrpush);
9622 }
9623 g_parsefile->strpush = sp;
9624 sp->prev_string = g_parsefile->next_to_pgetc;
9625 sp->prev_left_in_line = g_parsefile->left_in_line;
9626#if ENABLE_ASH_ALIAS
9627 sp->ap = ap;
9628 if (ap) {
9629 ap->flag |= ALIASINUSE;
9630 sp->string = s;
9631 }
9632#endif
9633 g_parsefile->next_to_pgetc = s;
9634 g_parsefile->left_in_line = len;
9635 INT_ON;
9636}
9637
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009638static void
9639popstring(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009640{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009641 struct strpush *sp = g_parsefile->strpush;
Eric Andersenc470f442003-07-28 09:56:35 +00009642
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009643 INT_OFF;
Denis Vlasenko131ae172007-02-18 13:00:19 +00009644#if ENABLE_ASH_ALIAS
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009645 if (sp->ap) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009646 if (g_parsefile->next_to_pgetc[-1] == ' '
9647 || g_parsefile->next_to_pgetc[-1] == '\t'
9648 ) {
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009649 checkkwd |= CHKALIAS;
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009650 }
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009651 if (sp->string != sp->ap->val) {
9652 free(sp->string);
9653 }
9654 sp->ap->flag &= ~ALIASINUSE;
9655 if (sp->ap->flag & ALIASDEAD) {
9656 unalias(sp->ap->name);
9657 }
Glenn L McGrath28939ad2004-07-21 10:20:19 +00009658 }
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009659#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009660 g_parsefile->next_to_pgetc = sp->prev_string;
9661 g_parsefile->left_in_line = sp->prev_left_in_line;
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009662 g_parsefile->strpush = sp->prev;
9663 if (sp != &(g_parsefile->basestrpush))
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009664 free(sp);
9665 INT_ON;
9666}
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009667
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009668//FIXME: BASH_COMPAT with "...&" does TWO pungetc():
9669//it peeks whether it is &>, and then pushes back both chars.
9670//This function needs to save last *next_to_pgetc to buf[0]
9671//to make two pungetc() reliable. Currently,
9672// pgetc (out of buf: does preadfd), pgetc, pungetc, pungetc won't work...
Denis Vlasenkoaa744452007-02-23 01:04:22 +00009673static int
9674preadfd(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009675{
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009676 int nr;
Denis Vlasenko6a0ad252008-07-25 13:34:05 +00009677 char *buf = g_parsefile->buf;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009678
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009679 g_parsefile->next_to_pgetc = buf;
Denis Vlasenko38f63192007-01-22 09:03:07 +00009680#if ENABLE_FEATURE_EDITING
Denis Vlasenko85c24712008-03-17 09:04:04 +00009681 retry:
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009682 if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
Denys Vlasenko80542ba2011-05-08 21:23:43 +02009683 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
Eric Andersenc470f442003-07-28 09:56:35 +00009684 else {
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009685 int timeout = -1;
9686# if ENABLE_ASH_IDLE_TIMEOUT
9687 if (iflag) {
9688 const char *tmout_var = lookupvar("TMOUT");
9689 if (tmout_var) {
9690 timeout = atoi(tmout_var) * 1000;
9691 if (timeout <= 0)
9692 timeout = -1;
9693 }
9694 }
9695# endif
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009696# if ENABLE_FEATURE_TAB_COMPLETION
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009697 line_input_state->path_lookup = pathval();
Denys Vlasenko8c52f802011-02-04 17:36:21 +01009698# endif
Denys Vlasenkoe9ab07c2014-08-13 18:00:08 +02009699 reinit_unicode_for_ash();
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009700 nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009701 if (nr == 0) {
9702 /* Ctrl+C pressed */
9703 if (trap[SIGINT]) {
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009704 buf[0] = '\n';
Denis Vlasenko8e1c7152007-01-22 07:21:38 +00009705 buf[1] = '\0';
Glenn L McGrath16e45d72004-02-04 08:24:39 +00009706 raise(SIGINT);
9707 return 1;
9708 }
Eric Andersenc470f442003-07-28 09:56:35 +00009709 goto retry;
9710 }
Denys Vlasenko66c5b122011-02-08 05:07:02 +01009711 if (nr < 0) {
9712 if (errno == 0) {
9713 /* Ctrl+D pressed */
9714 nr = 0;
9715 }
9716# if ENABLE_ASH_IDLE_TIMEOUT
9717 else if (errno == EAGAIN && timeout > 0) {
9718 printf("\007timed out waiting for input: auto-logout\n");
9719 exitshell();
9720 }
9721# endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +00009722 }
Eric Andersencb57d552001-06-28 07:25:16 +00009723 }
9724#else
Denys Vlasenko80542ba2011-05-08 21:23:43 +02009725 nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
Eric Andersencb57d552001-06-28 07:25:16 +00009726#endif
9727
Denys Vlasenko80c5b682011-05-08 21:21:10 +02009728#if 0 /* disabled: nonblock_immune_read() handles this problem */
Eric Andersencb57d552001-06-28 07:25:16 +00009729 if (nr < 0) {
Eric Andersencb57d552001-06-28 07:25:16 +00009730 if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
Denis Vlasenkod37f2222007-08-19 13:42:08 +00009731 int flags = fcntl(0, F_GETFL);
Denis Vlasenko9cb220b2007-12-09 10:03:28 +00009732 if (flags >= 0 && (flags & O_NONBLOCK)) {
9733 flags &= ~O_NONBLOCK;
Eric Andersencb57d552001-06-28 07:25:16 +00009734 if (fcntl(0, F_SETFL, flags) >= 0) {
9735 out2str("sh: turning off NDELAY mode\n");
9736 goto retry;
9737 }
9738 }
9739 }
9740 }
Denis Vlasenkoe376d452008-02-20 22:23:24 +00009741#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009742 return nr;
9743}
9744
9745/*
9746 * Refill the input buffer and return the next input character:
9747 *
9748 * 1) If a string was pushed back on the input, pop it;
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009749 * 2) If an EOF was pushed back (g_parsefile->left_in_line < -BIGNUM)
9750 * or we are reading from a string so we can't refill the buffer,
9751 * return EOF.
Denys Vlasenko883cea42009-07-11 15:31:59 +02009752 * 3) If there is more stuff in this buffer, use it else call read to fill it.
Eric Andersencb57d552001-06-28 07:25:16 +00009753 * 4) Process input up to the next newline, deleting nul characters.
9754 */
Denis Vlasenko727752d2008-11-28 03:41:47 +00009755//#define pgetc_debug(...) bb_error_msg(__VA_ARGS__)
9756#define pgetc_debug(...) ((void)0)
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009757static int
Eric Andersenc470f442003-07-28 09:56:35 +00009758preadbuffer(void)
Eric Andersencb57d552001-06-28 07:25:16 +00009759{
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009760 char *q;
Eric Andersencb57d552001-06-28 07:25:16 +00009761 int more;
Eric Andersencb57d552001-06-28 07:25:16 +00009762
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009763 while (g_parsefile->strpush) {
Denis Vlasenko131ae172007-02-18 13:00:19 +00009764#if ENABLE_ASH_ALIAS
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009765 if (g_parsefile->left_in_line == -1
9766 && g_parsefile->strpush->ap
9767 && g_parsefile->next_to_pgetc[-1] != ' '
9768 && g_parsefile->next_to_pgetc[-1] != '\t'
Denis Vlasenko16898402008-11-25 01:34:52 +00009769 ) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009770 pgetc_debug("preadbuffer PEOA");
Eric Andersencb57d552001-06-28 07:25:16 +00009771 return PEOA;
9772 }
Eric Andersen2870d962001-07-02 17:27:21 +00009773#endif
Eric Andersencb57d552001-06-28 07:25:16 +00009774 popstring();
Denis Vlasenko727752d2008-11-28 03:41:47 +00009775 /* try "pgetc" now: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009776 pgetc_debug("preadbuffer internal pgetc at %d:%p'%s'",
9777 g_parsefile->left_in_line,
9778 g_parsefile->next_to_pgetc,
9779 g_parsefile->next_to_pgetc);
9780 if (--g_parsefile->left_in_line >= 0)
9781 return (unsigned char)(*g_parsefile->next_to_pgetc++);
Eric Andersencb57d552001-06-28 07:25:16 +00009782 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009783 /* on both branches above g_parsefile->left_in_line < 0.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009784 * "pgetc" needs refilling.
9785 */
9786
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009787 /* -90 is our -BIGNUM. Below we use -99 to mark "EOF on read",
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009788 * pungetc() may increment it a few times.
Denis Vlasenkoe27dafd2008-11-28 04:01:03 +00009789 * Assuming it won't increment it to less than -90.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009790 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009791 if (g_parsefile->left_in_line < -90 || g_parsefile->buf == NULL) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009792 pgetc_debug("preadbuffer PEOF1");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009793 /* even in failure keep left_in_line and next_to_pgetc
9794 * in lock step, for correct multi-layer pungetc.
9795 * left_in_line was decremented before preadbuffer(),
9796 * must inc next_to_pgetc: */
9797 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009798 return PEOF;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009799 }
Eric Andersencb57d552001-06-28 07:25:16 +00009800
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009801 more = g_parsefile->left_in_buffer;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009802 if (more <= 0) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009803 flush_stdout_stderr();
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009804 again:
9805 more = preadfd();
9806 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009807 /* don't try reading again */
9808 g_parsefile->left_in_line = -99;
Denis Vlasenko727752d2008-11-28 03:41:47 +00009809 pgetc_debug("preadbuffer PEOF2");
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009810 g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009811 return PEOF;
9812 }
9813 }
9814
Denis Vlasenko727752d2008-11-28 03:41:47 +00009815 /* Find out where's the end of line.
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009816 * Set g_parsefile->left_in_line
9817 * and g_parsefile->left_in_buffer acordingly.
Denis Vlasenko727752d2008-11-28 03:41:47 +00009818 * NUL chars are deleted.
9819 */
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009820 q = g_parsefile->next_to_pgetc;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009821 for (;;) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009822 char c;
Eric Andersencb57d552001-06-28 07:25:16 +00009823
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009824 more--;
Eric Andersenc470f442003-07-28 09:56:35 +00009825
Denis Vlasenko727752d2008-11-28 03:41:47 +00009826 c = *q;
9827 if (c == '\0') {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009828 memmove(q, q + 1, more);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009829 } else {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009830 q++;
9831 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009832 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009833 break;
9834 }
Eric Andersencb57d552001-06-28 07:25:16 +00009835 }
9836
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009837 if (more <= 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009838 g_parsefile->left_in_line = q - g_parsefile->next_to_pgetc - 1;
9839 if (g_parsefile->left_in_line < 0)
Eric Andersencb57d552001-06-28 07:25:16 +00009840 goto again;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +00009841 break;
Eric Andersencb57d552001-06-28 07:25:16 +00009842 }
9843 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009844 g_parsefile->left_in_buffer = more;
Eric Andersencb57d552001-06-28 07:25:16 +00009845
Eric Andersencb57d552001-06-28 07:25:16 +00009846 if (vflag) {
Denis Vlasenko727752d2008-11-28 03:41:47 +00009847 char save = *q;
9848 *q = '\0';
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009849 out2str(g_parsefile->next_to_pgetc);
Denis Vlasenko727752d2008-11-28 03:41:47 +00009850 *q = save;
Eric Andersencb57d552001-06-28 07:25:16 +00009851 }
9852
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009853 pgetc_debug("preadbuffer at %d:%p'%s'",
9854 g_parsefile->left_in_line,
9855 g_parsefile->next_to_pgetc,
9856 g_parsefile->next_to_pgetc);
Denys Vlasenkocd716832009-11-28 22:14:02 +01009857 return (unsigned char)*g_parsefile->next_to_pgetc++;
Eric Andersencb57d552001-06-28 07:25:16 +00009858}
9859
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009860#define pgetc_as_macro() \
9861 (--g_parsefile->left_in_line >= 0 \
Denys Vlasenkocd716832009-11-28 22:14:02 +01009862 ? (unsigned char)*g_parsefile->next_to_pgetc++ \
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009863 : preadbuffer() \
9864 )
Denis Vlasenko727752d2008-11-28 03:41:47 +00009865
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009866static int
9867pgetc(void)
9868{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009869 pgetc_debug("pgetc_fast at %d:%p'%s'",
9870 g_parsefile->left_in_line,
9871 g_parsefile->next_to_pgetc,
9872 g_parsefile->next_to_pgetc);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009873 return pgetc_as_macro();
9874}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +00009875
9876#if ENABLE_ASH_OPTIMIZE_FOR_SIZE
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009877# define pgetc_fast() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009878#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009879# define pgetc_fast() pgetc_as_macro()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009880#endif
9881
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009882#if ENABLE_ASH_ALIAS
9883static int
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009884pgetc_without_PEOA(void)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009885{
9886 int c;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009887 do {
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009888 pgetc_debug("pgetc_fast at %d:%p'%s'",
9889 g_parsefile->left_in_line,
9890 g_parsefile->next_to_pgetc,
9891 g_parsefile->next_to_pgetc);
Denis Vlasenko834dee72008-10-07 09:18:30 +00009892 c = pgetc_fast();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009893 } while (c == PEOA);
9894 return c;
9895}
9896#else
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009897# define pgetc_without_PEOA() pgetc()
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009898#endif
9899
9900/*
9901 * Read a line from the script.
9902 */
9903static char *
9904pfgets(char *line, int len)
9905{
9906 char *p = line;
9907 int nleft = len;
9908 int c;
9909
9910 while (--nleft > 0) {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +01009911 c = pgetc_without_PEOA();
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009912 if (c == PEOF) {
9913 if (p == line)
9914 return NULL;
9915 break;
9916 }
9917 *p++ = c;
9918 if (c == '\n')
9919 break;
9920 }
9921 *p = '\0';
9922 return line;
9923}
9924
Eric Andersenc470f442003-07-28 09:56:35 +00009925/*
9926 * Undo the last call to pgetc. Only one character may be pushed back.
9927 * PEOF may be pushed back.
9928 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009929static void
Eric Andersenc470f442003-07-28 09:56:35 +00009930pungetc(void)
9931{
Denis Vlasenko41eb3002008-11-28 03:42:31 +00009932 g_parsefile->left_in_line++;
9933 g_parsefile->next_to_pgetc--;
9934 pgetc_debug("pushed back to %d:%p'%s'",
9935 g_parsefile->left_in_line,
9936 g_parsefile->next_to_pgetc,
9937 g_parsefile->next_to_pgetc);
Eric Andersencb57d552001-06-28 07:25:16 +00009938}
9939
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009940/*
9941 * To handle the "." command, a stack of input files is used. Pushfile
9942 * adds a new entry to the stack and popfile restores the previous level.
9943 */
Denis Vlasenko5cedb752007-02-18 19:56:41 +00009944static void
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009945pushfile(void)
Eric Andersenc470f442003-07-28 09:56:35 +00009946{
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009947 struct parsefile *pf;
9948
Denis Vlasenko597906c2008-02-20 16:38:54 +00009949 pf = ckzalloc(sizeof(*pf));
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009950 pf->prev = g_parsefile;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009951 pf->pf_fd = -1;
Denis Vlasenko597906c2008-02-20 16:38:54 +00009952 /*pf->strpush = NULL; - ckzalloc did it */
9953 /*pf->basestrpush.prev = NULL;*/
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009954 g_parsefile = pf;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009955}
9956
9957static void
9958popfile(void)
9959{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009960 struct parsefile *pf = g_parsefile;
Eric Andersenc470f442003-07-28 09:56:35 +00009961
Denis Vlasenkob012b102007-02-19 22:43:01 +00009962 INT_OFF;
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009963 if (pf->pf_fd >= 0)
9964 close(pf->pf_fd);
Denis Vlasenko60818682007-09-28 22:07:23 +00009965 free(pf->buf);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009966 while (pf->strpush)
9967 popstring();
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009968 g_parsefile = pf->prev;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009969 free(pf);
Denis Vlasenkob012b102007-02-19 22:43:01 +00009970 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +00009971}
9972
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009973/*
9974 * Return to top level.
9975 */
9976static void
9977popallfiles(void)
9978{
Denis Vlasenkob07a4962008-06-22 13:16:23 +00009979 while (g_parsefile != &basepf)
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009980 popfile();
9981}
9982
9983/*
9984 * Close the file(s) that the shell is reading commands from. Called
9985 * after a fork is done.
9986 */
9987static void
9988closescript(void)
9989{
9990 popallfiles();
Denys Vlasenko79b3d422010-06-03 04:29:08 +02009991 if (g_parsefile->pf_fd > 0) {
9992 close(g_parsefile->pf_fd);
9993 g_parsefile->pf_fd = 0;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +00009994 }
9995}
9996
9997/*
9998 * Like setinputfile, but takes an open file descriptor. Call this with
9999 * interrupts off.
10000 */
10001static void
10002setinputfd(int fd, int push)
10003{
Denis Vlasenko96e1b382007-09-30 23:50:48 +000010004 close_on_exec_on(fd);
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010005 if (push) {
10006 pushfile();
Denis Vlasenko727752d2008-11-28 03:41:47 +000010007 g_parsefile->buf = NULL;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010008 }
Denys Vlasenko79b3d422010-06-03 04:29:08 +020010009 g_parsefile->pf_fd = fd;
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010010 if (g_parsefile->buf == NULL)
10011 g_parsefile->buf = ckmalloc(IBUFSIZ);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010012 g_parsefile->left_in_buffer = 0;
10013 g_parsefile->left_in_line = 0;
10014 g_parsefile->linno = 1;
Denis Vlasenko4d2183b2007-02-23 01:05:38 +000010015}
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010016
Eric Andersenc470f442003-07-28 09:56:35 +000010017/*
10018 * Set the input to take input from a file. If push is set, push the
10019 * old input onto the stack first.
10020 */
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010021static int
10022setinputfile(const char *fname, int flags)
Eric Andersenc470f442003-07-28 09:56:35 +000010023{
10024 int fd;
10025 int fd2;
10026
Denis Vlasenkob012b102007-02-19 22:43:01 +000010027 INT_OFF;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010028 fd = open(fname, O_RDONLY);
10029 if (fd < 0) {
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010030 if (flags & INPUT_NOFILE_OK)
10031 goto out;
Denis Vlasenko9604e1b2009-03-03 18:47:56 +000010032 ash_msg_and_raise_error("can't open '%s'", fname);
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010033 }
Eric Andersenc470f442003-07-28 09:56:35 +000010034 if (fd < 10) {
10035 fd2 = copyfd(fd, 10);
10036 close(fd);
10037 if (fd2 < 0)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010038 ash_msg_and_raise_error("out of file descriptors");
Eric Andersenc470f442003-07-28 09:56:35 +000010039 fd = fd2;
10040 }
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010041 setinputfd(fd, flags & INPUT_PUSH_FILE);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010042 out:
Denis Vlasenkob012b102007-02-19 22:43:01 +000010043 INT_ON;
"Vladimir N. Oleynik"fb29b462006-01-15 14:21:01 +000010044 return fd;
Eric Andersenc470f442003-07-28 09:56:35 +000010045}
10046
Eric Andersencb57d552001-06-28 07:25:16 +000010047/*
10048 * Like setinputfile, but takes input from a string.
10049 */
Eric Andersenc470f442003-07-28 09:56:35 +000010050static void
10051setinputstring(char *string)
Eric Andersen62483552001-07-10 06:09:16 +000010052{
Denis Vlasenkob012b102007-02-19 22:43:01 +000010053 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010054 pushfile();
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010055 g_parsefile->next_to_pgetc = string;
10056 g_parsefile->left_in_line = strlen(string);
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010057 g_parsefile->buf = NULL;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000010058 g_parsefile->linno = 1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010059 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010060}
10061
10062
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010063/* ============ mail.c
10064 *
10065 * Routines to check for mail.
Eric Andersencb57d552001-06-28 07:25:16 +000010066 */
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010067
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010068#if ENABLE_ASH_MAIL
Eric Andersencb57d552001-06-28 07:25:16 +000010069
Eric Andersencb57d552001-06-28 07:25:16 +000010070#define MAXMBOXES 10
10071
Eric Andersenc470f442003-07-28 09:56:35 +000010072/* times of mailboxes */
10073static time_t mailtime[MAXMBOXES];
10074/* Set if MAIL or MAILPATH is changed. */
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010075static smallint mail_var_path_changed;
Eric Andersencb57d552001-06-28 07:25:16 +000010076
Eric Andersencb57d552001-06-28 07:25:16 +000010077/*
Eric Andersenc470f442003-07-28 09:56:35 +000010078 * Print appropriate message(s) if mail has arrived.
10079 * If mail_var_path_changed is set,
10080 * then the value of MAIL has mail_var_path_changed,
10081 * so we just update the values.
Eric Andersencb57d552001-06-28 07:25:16 +000010082 */
Eric Andersenc470f442003-07-28 09:56:35 +000010083static void
10084chkmail(void)
Eric Andersencb57d552001-06-28 07:25:16 +000010085{
Eric Andersencb57d552001-06-28 07:25:16 +000010086 const char *mpath;
10087 char *p;
10088 char *q;
Eric Andersenc470f442003-07-28 09:56:35 +000010089 time_t *mtp;
Eric Andersencb57d552001-06-28 07:25:16 +000010090 struct stackmark smark;
10091 struct stat statb;
10092
Eric Andersencb57d552001-06-28 07:25:16 +000010093 setstackmark(&smark);
Eric Andersenc470f442003-07-28 09:56:35 +000010094 mpath = mpathset() ? mpathval() : mailval();
10095 for (mtp = mailtime; mtp < mailtime + MAXMBOXES; mtp++) {
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020010096 p = path_advance(&mpath, nullstr);
Eric Andersencb57d552001-06-28 07:25:16 +000010097 if (p == NULL)
10098 break;
10099 if (*p == '\0')
10100 continue;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010101 for (q = p; *q; q++)
10102 continue;
Denis Vlasenkoa7189f02006-11-17 20:29:00 +000010103#if DEBUG
Eric Andersencb57d552001-06-28 07:25:16 +000010104 if (q[-1] != '/')
10105 abort();
10106#endif
Eric Andersenc470f442003-07-28 09:56:35 +000010107 q[-1] = '\0'; /* delete trailing '/' */
10108 if (stat(p, &statb) < 0) {
10109 *mtp = 0;
10110 continue;
Eric Andersencb57d552001-06-28 07:25:16 +000010111 }
Eric Andersenc470f442003-07-28 09:56:35 +000010112 if (!mail_var_path_changed && statb.st_mtime != *mtp) {
10113 fprintf(
Denys Vlasenkoea8b2522010-06-02 12:57:26 +020010114 stderr, "%s\n",
Eric Andersenc470f442003-07-28 09:56:35 +000010115 pathopt ? pathopt : "you have mail"
10116 );
10117 }
10118 *mtp = statb.st_mtime;
Eric Andersencb57d552001-06-28 07:25:16 +000010119 }
Eric Andersenc470f442003-07-28 09:56:35 +000010120 mail_var_path_changed = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010121 popstackmark(&smark);
10122}
Eric Andersencb57d552001-06-28 07:25:16 +000010123
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010124static void FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010125changemail(const char *val UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000010126{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010127 mail_var_path_changed = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000010128}
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010129
Denis Vlasenko131ae172007-02-18 13:00:19 +000010130#endif /* ASH_MAIL */
Eric Andersenc470f442003-07-28 09:56:35 +000010131
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010132
10133/* ============ ??? */
10134
Eric Andersencb57d552001-06-28 07:25:16 +000010135/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010136 * Set the shell parameters.
Eric Andersencb57d552001-06-28 07:25:16 +000010137 */
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010138static void
10139setparam(char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010140{
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010141 char **newparam;
10142 char **ap;
10143 int nparam;
Eric Andersencb57d552001-06-28 07:25:16 +000010144
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010145 for (nparam = 0; argv[nparam]; nparam++)
10146 continue;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010147 ap = newparam = ckmalloc((nparam + 1) * sizeof(*ap));
10148 while (*argv) {
10149 *ap++ = ckstrdup(*argv++);
Eric Andersencb57d552001-06-28 07:25:16 +000010150 }
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010151 *ap = NULL;
10152 freeparam(&shellparam);
Denis Vlasenko01631112007-12-16 17:20:38 +000010153 shellparam.malloced = 1;
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010154 shellparam.nparam = nparam;
10155 shellparam.p = newparam;
10156#if ENABLE_ASH_GETOPTS
10157 shellparam.optind = 1;
10158 shellparam.optoff = -1;
10159#endif
Eric Andersencb57d552001-06-28 07:25:16 +000010160}
10161
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010162/*
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000010163 * Process shell options. The global variable argptr contains a pointer
10164 * to the argument list; we advance it past the options.
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010165 *
10166 * SUSv3 section 2.8.1 "Consequences of Shell Errors" says:
10167 * For a non-interactive shell, an error condition encountered
10168 * by a special built-in ... shall cause the shell to write a diagnostic message
10169 * to standard error and exit as shown in the following table:
Denis Vlasenko56244732008-02-17 15:14:04 +000010170 * Error Special Built-In
Denis Vlasenko94e87bc2008-02-14 16:51:58 +000010171 * ...
10172 * Utility syntax error (option or operand error) Shall exit
10173 * ...
10174 * However, in bug 1142 (http://busybox.net/bugs/view.php?id=1142)
10175 * we see that bash does not do that (set "finishes" with error code 1 instead,
10176 * and shell continues), and people rely on this behavior!
10177 * Testcase:
10178 * set -o barfoo 2>/dev/null
10179 * echo $?
10180 *
10181 * Oh well. Let's mimic that.
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000010182 */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010183static int
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010184plus_minus_o(char *name, int val)
Eric Andersen62483552001-07-10 06:09:16 +000010185{
10186 int i;
10187
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010188 if (name) {
10189 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010190 if (strcmp(name, optnames(i)) == 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000010191 optlist[i] = val;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010192 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010193 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010194 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010195 ash_msg("illegal option %co %s", val ? '-' : '+', name);
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010196 return 1;
Eric Andersen62483552001-07-10 06:09:16 +000010197 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010198 for (i = 0; i < NOPTS; i++) {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010199 if (val) {
10200 out1fmt("%-16s%s\n", optnames(i), optlist[i] ? "on" : "off");
10201 } else {
10202 out1fmt("set %co %s\n", optlist[i] ? '-' : '+', optnames(i));
10203 }
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010204 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010205 return 0;
Eric Andersen62483552001-07-10 06:09:16 +000010206}
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010207static void
10208setoption(int flag, int val)
10209{
10210 int i;
10211
10212 for (i = 0; i < NOPTS; i++) {
10213 if (optletters(i) == flag) {
10214 optlist[i] = val;
10215 return;
10216 }
10217 }
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010218 ash_msg_and_raise_error("illegal option %c%c", val ? '-' : '+', flag);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010219 /* NOTREACHED */
10220}
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010221static int
Eric Andersenc470f442003-07-28 09:56:35 +000010222options(int cmdline)
Eric Andersencb57d552001-06-28 07:25:16 +000010223{
10224 char *p;
10225 int val;
10226 int c;
10227
10228 if (cmdline)
10229 minusc = NULL;
10230 while ((p = *argptr) != NULL) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010231 c = *p++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010232 if (c != '-' && c != '+')
10233 break;
10234 argptr++;
10235 val = 0; /* val = 0 if c == '+' */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010236 if (c == '-') {
Eric Andersencb57d552001-06-28 07:25:16 +000010237 val = 1;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010238 if (p[0] == '\0' || LONE_DASH(p)) {
Eric Andersen2870d962001-07-02 17:27:21 +000010239 if (!cmdline) {
10240 /* "-" means turn off -x and -v */
10241 if (p[0] == '\0')
10242 xflag = vflag = 0;
10243 /* "--" means reset params */
10244 else if (*argptr == NULL)
Eric Andersencb57d552001-06-28 07:25:16 +000010245 setparam(argptr);
Eric Andersen2870d962001-07-02 17:27:21 +000010246 }
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010247 break; /* "-" or "--" terminates options */
Eric Andersencb57d552001-06-28 07:25:16 +000010248 }
Eric Andersencb57d552001-06-28 07:25:16 +000010249 }
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010250 /* first char was + or - */
Eric Andersencb57d552001-06-28 07:25:16 +000010251 while ((c = *p++) != '\0') {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010252 /* bash 3.2 indeed handles -c CMD and +c CMD the same */
Eric Andersencb57d552001-06-28 07:25:16 +000010253 if (c == 'c' && cmdline) {
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010254 minusc = p; /* command is after shell args */
Eric Andersencb57d552001-06-28 07:25:16 +000010255 } else if (c == 'o') {
Denis Vlasenkodddfaff2008-05-06 15:30:27 +000010256 if (plus_minus_o(*argptr, val)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010257 /* it already printed err message */
10258 return 1; /* error */
10259 }
Eric Andersencb57d552001-06-28 07:25:16 +000010260 if (*argptr)
10261 argptr++;
Denis Vlasenko8fdc4b72007-07-14 11:33:10 +000010262 } else if (cmdline && (c == 'l')) { /* -l or +l == --login */
10263 isloginsh = 1;
10264 /* bash does not accept +-login, we also won't */
10265 } else if (cmdline && val && (c == '-')) { /* long options */
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010266 if (strcmp(p, "login") == 0)
Robert Griebl64f70cc2002-05-14 23:22:06 +000010267 isloginsh = 1;
10268 break;
Eric Andersencb57d552001-06-28 07:25:16 +000010269 } else {
10270 setoption(c, val);
10271 }
10272 }
10273 }
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010274 return 0;
Eric Andersencb57d552001-06-28 07:25:16 +000010275}
10276
Eric Andersencb57d552001-06-28 07:25:16 +000010277/*
Eric Andersencb57d552001-06-28 07:25:16 +000010278 * The shift builtin command.
10279 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010280static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010281shiftcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000010282{
10283 int n;
10284 char **ap1, **ap2;
10285
10286 n = 1;
Denis Vlasenko68404f12008-03-17 09:00:54 +000010287 if (argv[1])
Eric Andersencb57d552001-06-28 07:25:16 +000010288 n = number(argv[1]);
10289 if (n > shellparam.nparam)
Denis Vlasenkoc90e1be2008-07-30 15:35:05 +000010290 n = 0; /* bash compat, was = shellparam.nparam; */
Denis Vlasenkob012b102007-02-19 22:43:01 +000010291 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000010292 shellparam.nparam -= n;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010293 for (ap1 = shellparam.p; --n >= 0; ap1++) {
Denis Vlasenko01631112007-12-16 17:20:38 +000010294 if (shellparam.malloced)
Denis Vlasenkob012b102007-02-19 22:43:01 +000010295 free(*ap1);
Eric Andersencb57d552001-06-28 07:25:16 +000010296 }
10297 ap2 = shellparam.p;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000010298 while ((*ap2++ = *ap1++) != NULL)
10299 continue;
Denis Vlasenko131ae172007-02-18 13:00:19 +000010300#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010301 shellparam.optind = 1;
10302 shellparam.optoff = -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010303#endif
Denis Vlasenkob012b102007-02-19 22:43:01 +000010304 INT_ON;
Eric Andersencb57d552001-06-28 07:25:16 +000010305 return 0;
10306}
10307
Eric Andersencb57d552001-06-28 07:25:16 +000010308/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010309 * POSIX requires that 'set' (but not export or readonly) output the
10310 * variables in lexicographic order - by the locale's collating order (sigh).
10311 * Maybe we could keep them in an ordered balanced binary tree
10312 * instead of hashed lists.
10313 * For now just roll 'em through qsort for printing...
10314 */
10315static int
10316showvars(const char *sep_prefix, int on, int off)
10317{
10318 const char *sep;
10319 char **ep, **epend;
10320
10321 ep = listvars(on, off, &epend);
10322 qsort(ep, epend - ep, sizeof(char *), vpcmp);
10323
Denis Vlasenko2de3d9f2007-02-23 21:10:23 +000010324 sep = *sep_prefix ? " " : sep_prefix;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010325
10326 for (; ep < epend; ep++) {
10327 const char *p;
10328 const char *q;
10329
10330 p = strchrnul(*ep, '=');
10331 q = nullstr;
10332 if (*p)
10333 q = single_quote(++p);
10334 out1fmt("%s%s%.*s%s\n", sep_prefix, sep, (int)(p - *ep), *ep, q);
10335 }
10336 return 0;
10337}
10338
10339/*
Eric Andersencb57d552001-06-28 07:25:16 +000010340 * The set command builtin.
10341 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010342static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010343setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000010344{
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010345 int retval;
10346
Denis Vlasenko68404f12008-03-17 09:00:54 +000010347 if (!argv[1])
Eric Andersenc470f442003-07-28 09:56:35 +000010348 return showvars(nullstr, 0, VUNSET);
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010349
Denis Vlasenkob012b102007-02-19 22:43:01 +000010350 INT_OFF;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010010351 retval = options(/*cmdline:*/ 0);
10352 if (retval == 0) { /* if no parse error... */
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010353 optschanged();
10354 if (*argptr != NULL) {
10355 setparam(argptr);
10356 }
Eric Andersencb57d552001-06-28 07:25:16 +000010357 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000010358 INT_ON;
Denis Vlasenko28bf6712008-02-14 15:01:47 +000010359 return retval;
Eric Andersencb57d552001-06-28 07:25:16 +000010360}
10361
Denis Vlasenko131ae172007-02-18 13:00:19 +000010362#if ENABLE_ASH_RANDOM_SUPPORT
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010363static void FAST_FUNC
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000010364change_random(const char *value)
Eric Andersenef02f822004-03-11 13:34:24 +000010365{
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010366 uint32_t t;
10367
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010368 if (value == NULL) {
Eric Andersen16767e22004-03-16 05:14:10 +000010369 /* "get", generate */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010370 t = next_random(&random_gen);
Eric Andersen16767e22004-03-16 05:14:10 +000010371 /* set without recursion */
Denys Vlasenko8837c5d2010-06-02 12:56:18 +020010372 setvar(vrandom.var_text, utoa(t), VNOFUNC);
Eric Andersen16767e22004-03-16 05:14:10 +000010373 vrandom.flags &= ~VNOFUNC;
10374 } else {
10375 /* set/reset */
Denys Vlasenko3ea2e822009-10-09 20:59:04 +020010376 t = strtoul(value, NULL, 10);
10377 INIT_RANDOM_T(&random_gen, (t ? t : 1), t);
Eric Andersen16767e22004-03-16 05:14:10 +000010378 }
Eric Andersenef02f822004-03-11 13:34:24 +000010379}
Eric Andersen16767e22004-03-16 05:14:10 +000010380#endif
10381
Denis Vlasenko131ae172007-02-18 13:00:19 +000010382#if ENABLE_ASH_GETOPTS
Eric Andersencb57d552001-06-28 07:25:16 +000010383static int
Eric Andersenc470f442003-07-28 09:56:35 +000010384getopts(char *optstr, char *optvar, char **optfirst, int *param_optind, int *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010385{
10386 char *p, *q;
10387 char c = '?';
10388 int done = 0;
10389 int err = 0;
Eric Andersena48b0a32003-10-22 10:56:47 +000010390 char s[12];
10391 char **optnext;
Eric Andersencb57d552001-06-28 07:25:16 +000010392
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010393 if (*param_optind < 1)
Eric Andersena48b0a32003-10-22 10:56:47 +000010394 return 1;
10395 optnext = optfirst + *param_optind - 1;
10396
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000010397 if (*param_optind <= 1 || *optoff < 0 || (int)strlen(optnext[-1]) < *optoff)
Eric Andersencb57d552001-06-28 07:25:16 +000010398 p = NULL;
10399 else
Eric Andersena48b0a32003-10-22 10:56:47 +000010400 p = optnext[-1] + *optoff;
Eric Andersencb57d552001-06-28 07:25:16 +000010401 if (p == NULL || *p == '\0') {
10402 /* Current word is done, advance */
Eric Andersencb57d552001-06-28 07:25:16 +000010403 p = *optnext;
10404 if (p == NULL || *p != '-' || *++p == '\0') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010405 atend:
Eric Andersencb57d552001-06-28 07:25:16 +000010406 p = NULL;
10407 done = 1;
10408 goto out;
10409 }
10410 optnext++;
Denis Vlasenko9f739442006-12-16 23:49:13 +000010411 if (LONE_DASH(p)) /* check for "--" */
Eric Andersencb57d552001-06-28 07:25:16 +000010412 goto atend;
10413 }
10414
10415 c = *p++;
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000010416 for (q = optstr; *q != c;) {
Eric Andersencb57d552001-06-28 07:25:16 +000010417 if (*q == '\0') {
10418 if (optstr[0] == ':') {
10419 s[0] = c;
10420 s[1] = '\0';
10421 err |= setvarsafe("OPTARG", s, 0);
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010422 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010423 fprintf(stderr, "Illegal option -%c\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010424 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010425 }
10426 c = '?';
Eric Andersenc470f442003-07-28 09:56:35 +000010427 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010428 }
10429 if (*++q == ':')
10430 q++;
10431 }
10432
10433 if (*++q == ':') {
10434 if (*p == '\0' && (p = *optnext) == NULL) {
10435 if (optstr[0] == ':') {
10436 s[0] = c;
10437 s[1] = '\0';
10438 err |= setvarsafe("OPTARG", s, 0);
10439 c = ':';
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010440 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010441 fprintf(stderr, "No arg for -%c option\n", c);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010442 unsetvar("OPTARG");
Eric Andersencb57d552001-06-28 07:25:16 +000010443 c = '?';
10444 }
Eric Andersenc470f442003-07-28 09:56:35 +000010445 goto out;
Eric Andersencb57d552001-06-28 07:25:16 +000010446 }
10447
10448 if (p == *optnext)
10449 optnext++;
Eric Andersenc470f442003-07-28 09:56:35 +000010450 err |= setvarsafe("OPTARG", p, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000010451 p = NULL;
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010452 } else
Eric Andersenc470f442003-07-28 09:56:35 +000010453 err |= setvarsafe("OPTARG", nullstr, 0);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010454 out:
Eric Andersencb57d552001-06-28 07:25:16 +000010455 *optoff = p ? p - *(optnext - 1) : -1;
Eric Andersenc470f442003-07-28 09:56:35 +000010456 *param_optind = optnext - optfirst + 1;
10457 fmtstr(s, sizeof(s), "%d", *param_optind);
Eric Andersencb57d552001-06-28 07:25:16 +000010458 err |= setvarsafe("OPTIND", s, VNOFUNC);
10459 s[0] = c;
10460 s[1] = '\0';
10461 err |= setvarsafe(optvar, s, 0);
10462 if (err) {
Eric Andersenc470f442003-07-28 09:56:35 +000010463 *param_optind = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010464 *optoff = -1;
Denis Vlasenkob012b102007-02-19 22:43:01 +000010465 flush_stdout_stderr();
10466 raise_exception(EXERROR);
Eric Andersencb57d552001-06-28 07:25:16 +000010467 }
10468 return done;
10469}
Eric Andersenc470f442003-07-28 09:56:35 +000010470
10471/*
10472 * The getopts builtin. Shellparam.optnext points to the next argument
10473 * to be processed. Shellparam.optptr points to the next character to
10474 * be processed in the current argument. If shellparam.optnext is NULL,
10475 * then it's the first time getopts has been called.
10476 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020010477static int FAST_FUNC
Eric Andersenc470f442003-07-28 09:56:35 +000010478getoptscmd(int argc, char **argv)
10479{
10480 char **optbase;
10481
10482 if (argc < 3)
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000010483 ash_msg_and_raise_error("usage: getopts optstring var [arg]");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010484 if (argc == 3) {
Eric Andersenc470f442003-07-28 09:56:35 +000010485 optbase = shellparam.p;
10486 if (shellparam.optind > shellparam.nparam + 1) {
10487 shellparam.optind = 1;
10488 shellparam.optoff = -1;
10489 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010490 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010491 optbase = &argv[3];
10492 if (shellparam.optind > argc - 2) {
10493 shellparam.optind = 1;
10494 shellparam.optoff = -1;
10495 }
10496 }
10497
10498 return getopts(argv[1], argv[2], optbase, &shellparam.optind,
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000010499 &shellparam.optoff);
Eric Andersenc470f442003-07-28 09:56:35 +000010500}
Denis Vlasenko131ae172007-02-18 13:00:19 +000010501#endif /* ASH_GETOPTS */
Eric Andersencb57d552001-06-28 07:25:16 +000010502
Eric Andersencb57d552001-06-28 07:25:16 +000010503
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010504/* ============ Shell parser */
Eric Andersencb57d552001-06-28 07:25:16 +000010505
Denis Vlasenkob07a4962008-06-22 13:16:23 +000010506struct heredoc {
10507 struct heredoc *next; /* next here document in list */
10508 union node *here; /* redirection node */
10509 char *eofmark; /* string indicating end of input */
10510 smallint striptabs; /* if set, strip leading tabs */
10511};
10512
10513static smallint tokpushback; /* last token pushed back */
10514static smallint parsebackquote; /* nonzero if we are inside backquotes */
10515static smallint quoteflag; /* set if (part of) last token was quoted */
10516static token_id_t lasttoken; /* last token read (integer id Txxx) */
10517static struct heredoc *heredoclist; /* list of here documents to read */
10518static char *wordtext; /* text of last word returned by readtoken */
10519static struct nodelist *backquotelist;
10520static union node *redirnode;
10521static struct heredoc *heredoc;
Denis Vlasenko99eb8502007-02-23 21:09:49 +000010522
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010523static const char *
10524tokname(char *buf, int tok)
10525{
10526 if (tok < TSEMI)
10527 return tokname_array[tok] + 1;
10528 sprintf(buf, "\"%s\"", tokname_array[tok] + 1);
10529 return buf;
10530}
10531
10532/* raise_error_unexpected_syntax:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010533 * Called when an unexpected token is read during the parse. The argument
10534 * is the token that is expected, or -1 if more than one type of token can
10535 * occur at this point.
10536 */
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000010537static void raise_error_unexpected_syntax(int) NORETURN;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010538static void
10539raise_error_unexpected_syntax(int token)
10540{
10541 char msg[64];
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010542 char buf[16];
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010543 int l;
10544
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010545 l = sprintf(msg, "unexpected %s", tokname(buf, lasttoken));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010546 if (token >= 0)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010547 sprintf(msg + l, " (expecting %s)", tokname(buf, token));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010548 raise_error_syntax(msg);
10549 /* NOTREACHED */
10550}
Eric Andersencb57d552001-06-28 07:25:16 +000010551
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010552#define EOFMARKLEN 79
Eric Andersencb57d552001-06-28 07:25:16 +000010553
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010554/* parsing is heavily cross-recursive, need these forward decls */
10555static union node *andor(void);
10556static union node *pipeline(void);
10557static union node *parse_command(void);
10558static void parseheredoc(void);
10559static char peektoken(void);
10560static int readtoken(void);
Eric Andersencb57d552001-06-28 07:25:16 +000010561
Eric Andersenc470f442003-07-28 09:56:35 +000010562static union node *
10563list(int nlflag)
Eric Andersencb57d552001-06-28 07:25:16 +000010564{
10565 union node *n1, *n2, *n3;
10566 int tok;
10567
Eric Andersenc470f442003-07-28 09:56:35 +000010568 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10569 if (nlflag == 2 && peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +000010570 return NULL;
10571 n1 = NULL;
10572 for (;;) {
10573 n2 = andor();
10574 tok = readtoken();
10575 if (tok == TBACKGND) {
Eric Andersenc470f442003-07-28 09:56:35 +000010576 if (n2->type == NPIPE) {
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010577 n2->npipe.pipe_backgnd = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010578 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000010579 if (n2->type != NREDIR) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010580 n3 = stzalloc(sizeof(struct nredir));
Eric Andersenc470f442003-07-28 09:56:35 +000010581 n3->nredir.n = n2;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010582 /*n3->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010583 n2 = n3;
10584 }
10585 n2->type = NBACKGND;
Eric Andersencb57d552001-06-28 07:25:16 +000010586 }
10587 }
10588 if (n1 == NULL) {
10589 n1 = n2;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010590 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010591 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010592 n3->type = NSEMI;
10593 n3->nbinary.ch1 = n1;
10594 n3->nbinary.ch2 = n2;
10595 n1 = n3;
10596 }
10597 switch (tok) {
10598 case TBACKGND:
10599 case TSEMI:
10600 tok = readtoken();
10601 /* fall through */
10602 case TNL:
10603 if (tok == TNL) {
10604 parseheredoc();
Eric Andersenc470f442003-07-28 09:56:35 +000010605 if (nlflag == 1)
Eric Andersencb57d552001-06-28 07:25:16 +000010606 return n1;
10607 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010608 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010609 }
Eric Andersenc470f442003-07-28 09:56:35 +000010610 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Manuel Novoa III 16815d42001-08-10 19:36:07 +000010611 if (peektoken())
Eric Andersencb57d552001-06-28 07:25:16 +000010612 return n1;
10613 break;
10614 case TEOF:
10615 if (heredoclist)
10616 parseheredoc();
10617 else
Eric Andersenc470f442003-07-28 09:56:35 +000010618 pungetc(); /* push back EOF on input */
Eric Andersencb57d552001-06-28 07:25:16 +000010619 return n1;
10620 default:
Eric Andersenc470f442003-07-28 09:56:35 +000010621 if (nlflag == 1)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010622 raise_error_unexpected_syntax(-1);
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010623 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010624 return n1;
10625 }
10626 }
10627}
10628
Eric Andersenc470f442003-07-28 09:56:35 +000010629static union node *
10630andor(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010631{
Eric Andersencb57d552001-06-28 07:25:16 +000010632 union node *n1, *n2, *n3;
10633 int t;
10634
Eric Andersencb57d552001-06-28 07:25:16 +000010635 n1 = pipeline();
10636 for (;;) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000010637 t = readtoken();
10638 if (t == TAND) {
Eric Andersencb57d552001-06-28 07:25:16 +000010639 t = NAND;
10640 } else if (t == TOR) {
10641 t = NOR;
10642 } else {
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010643 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010644 return n1;
10645 }
Eric Andersenc470f442003-07-28 09:56:35 +000010646 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010647 n2 = pipeline();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010648 n3 = stzalloc(sizeof(struct nbinary));
Eric Andersencb57d552001-06-28 07:25:16 +000010649 n3->type = t;
10650 n3->nbinary.ch1 = n1;
10651 n3->nbinary.ch2 = n2;
10652 n1 = n3;
10653 }
10654}
10655
Eric Andersenc470f442003-07-28 09:56:35 +000010656static union node *
10657pipeline(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010658{
Eric Andersencb57d552001-06-28 07:25:16 +000010659 union node *n1, *n2, *pipenode;
10660 struct nodelist *lp, *prev;
10661 int negate;
10662
10663 negate = 0;
10664 TRACE(("pipeline: entered\n"));
10665 if (readtoken() == TNOT) {
10666 negate = !negate;
Eric Andersenc470f442003-07-28 09:56:35 +000010667 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010668 } else
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010669 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010670 n1 = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010671 if (readtoken() == TPIPE) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010672 pipenode = stzalloc(sizeof(struct npipe));
Eric Andersencb57d552001-06-28 07:25:16 +000010673 pipenode->type = NPIPE;
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010674 /*pipenode->npipe.pipe_backgnd = 0; - stzalloc did it */
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010675 lp = stzalloc(sizeof(struct nodelist));
Eric Andersencb57d552001-06-28 07:25:16 +000010676 pipenode->npipe.cmdlist = lp;
10677 lp->n = n1;
10678 do {
10679 prev = lp;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010680 lp = stzalloc(sizeof(struct nodelist));
Eric Andersenc470f442003-07-28 09:56:35 +000010681 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010682 lp->n = parse_command();
Eric Andersencb57d552001-06-28 07:25:16 +000010683 prev->next = lp;
10684 } while (readtoken() == TPIPE);
10685 lp->next = NULL;
10686 n1 = pipenode;
10687 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010688 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010689 if (negate) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010690 n2 = stzalloc(sizeof(struct nnot));
Eric Andersencb57d552001-06-28 07:25:16 +000010691 n2->type = NNOT;
10692 n2->nnot.com = n1;
10693 return n2;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000010694 }
10695 return n1;
Eric Andersencb57d552001-06-28 07:25:16 +000010696}
10697
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010698static union node *
10699makename(void)
10700{
10701 union node *n;
10702
Denis Vlasenko597906c2008-02-20 16:38:54 +000010703 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010704 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010705 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010706 n->narg.text = wordtext;
10707 n->narg.backquote = backquotelist;
10708 return n;
10709}
10710
10711static void
10712fixredir(union node *n, const char *text, int err)
10713{
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010714 int fd;
10715
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010716 TRACE(("Fix redir %s %d\n", text, err));
10717 if (!err)
10718 n->ndup.vname = NULL;
10719
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000010720 fd = bb_strtou(text, NULL, 10);
10721 if (!errno && fd >= 0)
10722 n->ndup.dupfd = fd;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010723 else if (LONE_DASH(text))
10724 n->ndup.dupfd = -1;
10725 else {
10726 if (err)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010727 raise_error_syntax("bad fd number");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010728 n->ndup.vname = makename();
10729 }
10730}
10731
10732/*
10733 * Returns true if the text contains nothing to expand (no dollar signs
10734 * or backquotes).
10735 */
10736static int
Denis Vlasenko68819d12008-12-15 11:26:36 +000010737noexpand(const char *text)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010738{
Denys Vlasenkocd716832009-11-28 22:14:02 +010010739 unsigned char c;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010740
Denys Vlasenkocd716832009-11-28 22:14:02 +010010741 while ((c = *text++) != '\0') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010742 if (c == CTLQUOTEMARK)
10743 continue;
10744 if (c == CTLESC)
Denys Vlasenkocd716832009-11-28 22:14:02 +010010745 text++;
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010010746 else if (SIT(c, BASESYNTAX) == CCTL)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010747 return 0;
10748 }
10749 return 1;
10750}
10751
10752static void
10753parsefname(void)
10754{
10755 union node *n = redirnode;
10756
10757 if (readtoken() != TWORD)
10758 raise_error_unexpected_syntax(-1);
10759 if (n->type == NHERE) {
10760 struct heredoc *here = heredoc;
10761 struct heredoc *p;
10762 int i;
10763
10764 if (quoteflag == 0)
10765 n->type = NXHERE;
10766 TRACE(("Here document %d\n", n->type));
10767 if (!noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
Denis Vlasenko559691a2008-10-05 18:39:31 +000010768 raise_error_syntax("illegal eof marker for << redirection");
Denys Vlasenkob6c84342009-08-29 20:23:20 +020010769 rmescapes(wordtext, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010770 here->eofmark = wordtext;
10771 here->next = NULL;
10772 if (heredoclist == NULL)
10773 heredoclist = here;
10774 else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010775 for (p = heredoclist; p->next; p = p->next)
10776 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010777 p->next = here;
10778 }
10779 } else if (n->type == NTOFD || n->type == NFROMFD) {
10780 fixredir(n, wordtext, 0);
10781 } else {
10782 n->nfile.fname = makename();
10783 }
10784}
Eric Andersencb57d552001-06-28 07:25:16 +000010785
Eric Andersenc470f442003-07-28 09:56:35 +000010786static union node *
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010787simplecmd(void)
10788{
10789 union node *args, **app;
10790 union node *n = NULL;
10791 union node *vars, **vpp;
10792 union node **rpp, *redir;
10793 int savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010794#if ENABLE_ASH_BASH_COMPAT
10795 smallint double_brackets_flag = 0;
10796#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010797
10798 args = NULL;
10799 app = &args;
10800 vars = NULL;
10801 vpp = &vars;
10802 redir = NULL;
10803 rpp = &redir;
10804
10805 savecheckkwd = CHKALIAS;
10806 for (;;) {
Denis Vlasenko80591b02008-03-25 07:49:43 +000010807 int t;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010808 checkkwd = savecheckkwd;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010809 t = readtoken();
10810 switch (t) {
10811#if ENABLE_ASH_BASH_COMPAT
10812 case TAND: /* "&&" */
10813 case TOR: /* "||" */
10814 if (!double_brackets_flag) {
10815 tokpushback = 1;
10816 goto out;
10817 }
10818 wordtext = (char *) (t == TAND ? "-a" : "-o");
10819#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010820 case TWORD:
Denis Vlasenko597906c2008-02-20 16:38:54 +000010821 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010822 n->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010823 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010824 n->narg.text = wordtext;
Denis Vlasenko80591b02008-03-25 07:49:43 +000010825#if ENABLE_ASH_BASH_COMPAT
10826 if (strcmp("[[", wordtext) == 0)
10827 double_brackets_flag = 1;
10828 else if (strcmp("]]", wordtext) == 0)
10829 double_brackets_flag = 0;
10830#endif
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010831 n->narg.backquote = backquotelist;
10832 if (savecheckkwd && isassignment(wordtext)) {
10833 *vpp = n;
10834 vpp = &n->narg.next;
10835 } else {
10836 *app = n;
10837 app = &n->narg.next;
10838 savecheckkwd = 0;
10839 }
10840 break;
10841 case TREDIR:
10842 *rpp = n = redirnode;
10843 rpp = &n->nfile.next;
10844 parsefname(); /* read name of redirection file */
10845 break;
10846 case TLP:
10847 if (args && app == &args->narg.next
10848 && !vars && !redir
10849 ) {
10850 struct builtincmd *bcmd;
10851 const char *name;
10852
10853 /* We have a function */
10854 if (readtoken() != TRP)
10855 raise_error_unexpected_syntax(TRP);
10856 name = n->narg.text;
10857 if (!goodname(name)
10858 || ((bcmd = find_builtin(name)) && IS_BUILTIN_SPECIAL(bcmd))
10859 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000010860 raise_error_syntax("bad function name");
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010861 }
10862 n->type = NDEFUN;
10863 checkkwd = CHKNL | CHKKWD | CHKALIAS;
10864 n->narg.next = parse_command();
10865 return n;
10866 }
10867 /* fall through */
10868 default:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010869 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010870 goto out;
10871 }
10872 }
10873 out:
10874 *app = NULL;
10875 *vpp = NULL;
10876 *rpp = NULL;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010877 n = stzalloc(sizeof(struct ncmd));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010878 n->type = NCMD;
10879 n->ncmd.args = args;
10880 n->ncmd.assign = vars;
10881 n->ncmd.redirect = redir;
10882 return n;
10883}
10884
10885static union node *
10886parse_command(void)
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000010887{
Eric Andersencb57d552001-06-28 07:25:16 +000010888 union node *n1, *n2;
10889 union node *ap, **app;
10890 union node *cp, **cpp;
10891 union node *redir, **rpp;
Eric Andersenc470f442003-07-28 09:56:35 +000010892 union node **rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000010893 int t;
10894
10895 redir = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000010896 rpp2 = &redir;
Eric Andersen88cec252001-09-06 17:35:20 +000010897
Eric Andersencb57d552001-06-28 07:25:16 +000010898 switch (readtoken()) {
Eric Andersenc470f442003-07-28 09:56:35 +000010899 default:
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010900 raise_error_unexpected_syntax(-1);
Eric Andersenc470f442003-07-28 09:56:35 +000010901 /* NOTREACHED */
Eric Andersencb57d552001-06-28 07:25:16 +000010902 case TIF:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010903 n1 = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010904 n1->type = NIF;
10905 n1->nif.test = list(0);
10906 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010907 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010908 n1->nif.ifpart = list(0);
10909 n2 = n1;
10910 while (readtoken() == TELIF) {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010911 n2->nif.elsepart = stzalloc(sizeof(struct nif));
Eric Andersencb57d552001-06-28 07:25:16 +000010912 n2 = n2->nif.elsepart;
10913 n2->type = NIF;
10914 n2->nif.test = list(0);
10915 if (readtoken() != TTHEN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010916 raise_error_unexpected_syntax(TTHEN);
Eric Andersencb57d552001-06-28 07:25:16 +000010917 n2->nif.ifpart = list(0);
10918 }
10919 if (lasttoken == TELSE)
10920 n2->nif.elsepart = list(0);
10921 else {
10922 n2->nif.elsepart = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010923 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010924 }
Eric Andersenc470f442003-07-28 09:56:35 +000010925 t = TFI;
Eric Andersencb57d552001-06-28 07:25:16 +000010926 break;
10927 case TWHILE:
Eric Andersenc470f442003-07-28 09:56:35 +000010928 case TUNTIL: {
Eric Andersencb57d552001-06-28 07:25:16 +000010929 int got;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010930 n1 = stzalloc(sizeof(struct nbinary));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010931 n1->type = (lasttoken == TWHILE) ? NWHILE : NUNTIL;
Eric Andersencb57d552001-06-28 07:25:16 +000010932 n1->nbinary.ch1 = list(0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000010933 got = readtoken();
10934 if (got != TDO) {
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020010935 TRACE(("expecting DO got '%s' %s\n", tokname_array[got] + 1,
Denis Vlasenko131ae172007-02-18 13:00:19 +000010936 got == TWORD ? wordtext : ""));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010937 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010938 }
10939 n1->nbinary.ch2 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010940 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010941 break;
10942 }
10943 case TFOR:
Denis Vlasenko2dc240c2008-07-24 06:07:50 +000010944 if (readtoken() != TWORD || quoteflag || !goodname(wordtext))
Denis Vlasenko559691a2008-10-05 18:39:31 +000010945 raise_error_syntax("bad for loop variable");
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010946 n1 = stzalloc(sizeof(struct nfor));
Eric Andersencb57d552001-06-28 07:25:16 +000010947 n1->type = NFOR;
10948 n1->nfor.var = wordtext;
Eric Andersenc470f442003-07-28 09:56:35 +000010949 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010950 if (readtoken() == TIN) {
10951 app = &ap;
10952 while (readtoken() == TWORD) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010953 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010954 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010955 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010956 n2->narg.text = wordtext;
10957 n2->narg.backquote = backquotelist;
10958 *app = n2;
10959 app = &n2->narg.next;
10960 }
10961 *app = NULL;
10962 n1->nfor.args = ap;
10963 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010964 raise_error_unexpected_syntax(-1);
Eric Andersencb57d552001-06-28 07:25:16 +000010965 } else {
Denis Vlasenko597906c2008-02-20 16:38:54 +000010966 n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010967 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010968 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000010969 n2->narg.text = (char *)dolatstr;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010970 /*n2->narg.backquote = NULL;*/
Eric Andersencb57d552001-06-28 07:25:16 +000010971 n1->nfor.args = n2;
10972 /*
10973 * Newline or semicolon here is optional (but note
10974 * that the original Bourne shell only allowed NL).
10975 */
10976 if (lasttoken != TNL && lasttoken != TSEMI)
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000010977 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000010978 }
Eric Andersenc470f442003-07-28 09:56:35 +000010979 checkkwd = CHKNL | CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010980 if (readtoken() != TDO)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010981 raise_error_unexpected_syntax(TDO);
Eric Andersencb57d552001-06-28 07:25:16 +000010982 n1->nfor.body = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000010983 t = TDONE;
Eric Andersencb57d552001-06-28 07:25:16 +000010984 break;
10985 case TCASE:
Denis Vlasenko838ffd52008-02-21 04:32:08 +000010986 n1 = stzalloc(sizeof(struct ncase));
Eric Andersencb57d552001-06-28 07:25:16 +000010987 n1->type = NCASE;
10988 if (readtoken() != TWORD)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010989 raise_error_unexpected_syntax(TWORD);
Denis Vlasenko597906c2008-02-20 16:38:54 +000010990 n1->ncase.expr = n2 = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000010991 n2->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000010992 /*n2->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000010993 n2->narg.text = wordtext;
10994 n2->narg.backquote = backquotelist;
Eric Andersencb57d552001-06-28 07:25:16 +000010995 do {
Eric Andersenc470f442003-07-28 09:56:35 +000010996 checkkwd = CHKKWD | CHKALIAS;
Eric Andersencb57d552001-06-28 07:25:16 +000010997 } while (readtoken() == TNL);
10998 if (lasttoken != TIN)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000010999 raise_error_unexpected_syntax(TIN);
Eric Andersencb57d552001-06-28 07:25:16 +000011000 cpp = &n1->ncase.cases;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011001 next_case:
Eric Andersenc470f442003-07-28 09:56:35 +000011002 checkkwd = CHKNL | CHKKWD;
11003 t = readtoken();
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011004 while (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011005 if (lasttoken == TLP)
11006 readtoken();
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011007 *cpp = cp = stzalloc(sizeof(struct nclist));
Eric Andersencb57d552001-06-28 07:25:16 +000011008 cp->type = NCLIST;
11009 app = &cp->nclist.pattern;
11010 for (;;) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011011 *app = ap = stzalloc(sizeof(struct narg));
Eric Andersencb57d552001-06-28 07:25:16 +000011012 ap->type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011013 /*ap->narg.next = NULL; - stzalloc did it */
Eric Andersencb57d552001-06-28 07:25:16 +000011014 ap->narg.text = wordtext;
11015 ap->narg.backquote = backquotelist;
Eric Andersenc470f442003-07-28 09:56:35 +000011016 if (readtoken() != TPIPE)
Eric Andersencb57d552001-06-28 07:25:16 +000011017 break;
11018 app = &ap->narg.next;
11019 readtoken();
11020 }
Denis Vlasenko597906c2008-02-20 16:38:54 +000011021 //ap->narg.next = NULL;
Eric Andersencb57d552001-06-28 07:25:16 +000011022 if (lasttoken != TRP)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011023 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011024 cp->nclist.body = list(2);
Eric Andersencb57d552001-06-28 07:25:16 +000011025
Eric Andersenc470f442003-07-28 09:56:35 +000011026 cpp = &cp->nclist.next;
11027
11028 checkkwd = CHKNL | CHKKWD;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011029 t = readtoken();
11030 if (t != TESAC) {
Eric Andersencb57d552001-06-28 07:25:16 +000011031 if (t != TENDCASE)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011032 raise_error_unexpected_syntax(TENDCASE);
11033 goto next_case;
Eric Andersencb57d552001-06-28 07:25:16 +000011034 }
Eric Andersenc470f442003-07-28 09:56:35 +000011035 }
Eric Andersencb57d552001-06-28 07:25:16 +000011036 *cpp = NULL;
Eric Andersenc470f442003-07-28 09:56:35 +000011037 goto redir;
Eric Andersencb57d552001-06-28 07:25:16 +000011038 case TLP:
Denis Vlasenko597906c2008-02-20 16:38:54 +000011039 n1 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011040 n1->type = NSUBSHELL;
11041 n1->nredir.n = list(0);
Denis Vlasenko597906c2008-02-20 16:38:54 +000011042 /*n1->nredir.redirect = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011043 t = TRP;
Eric Andersencb57d552001-06-28 07:25:16 +000011044 break;
11045 case TBEGIN:
11046 n1 = list(0);
Eric Andersenc470f442003-07-28 09:56:35 +000011047 t = TEND;
Eric Andersencb57d552001-06-28 07:25:16 +000011048 break;
Eric Andersencb57d552001-06-28 07:25:16 +000011049 case TWORD:
Eric Andersenc470f442003-07-28 09:56:35 +000011050 case TREDIR:
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011051 tokpushback = 1;
Eric Andersenc470f442003-07-28 09:56:35 +000011052 return simplecmd();
Eric Andersencb57d552001-06-28 07:25:16 +000011053 }
11054
Eric Andersenc470f442003-07-28 09:56:35 +000011055 if (readtoken() != t)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011056 raise_error_unexpected_syntax(t);
Eric Andersenc470f442003-07-28 09:56:35 +000011057
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011058 redir:
Eric Andersencb57d552001-06-28 07:25:16 +000011059 /* Now check for redirection which may follow command */
Eric Andersenc470f442003-07-28 09:56:35 +000011060 checkkwd = CHKKWD | CHKALIAS;
11061 rpp = rpp2;
Eric Andersencb57d552001-06-28 07:25:16 +000011062 while (readtoken() == TREDIR) {
11063 *rpp = n2 = redirnode;
11064 rpp = &n2->nfile.next;
11065 parsefname();
11066 }
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011067 tokpushback = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011068 *rpp = NULL;
11069 if (redir) {
11070 if (n1->type != NSUBSHELL) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011071 n2 = stzalloc(sizeof(struct nredir));
Eric Andersencb57d552001-06-28 07:25:16 +000011072 n2->type = NREDIR;
11073 n2->nredir.n = n1;
11074 n1 = n2;
11075 }
11076 n1->nredir.redirect = redir;
11077 }
Eric Andersencb57d552001-06-28 07:25:16 +000011078 return n1;
11079}
11080
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011081#if ENABLE_ASH_BASH_COMPAT
11082static int decode_dollar_squote(void)
11083{
11084 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
11085 int c, cnt;
11086 char *p;
11087 char buf[4];
11088
11089 c = pgetc();
11090 p = strchr(C_escapes, c);
11091 if (p) {
11092 buf[0] = c;
11093 p = buf;
11094 cnt = 3;
11095 if ((unsigned char)(c - '0') <= 7) { /* \ooo */
11096 do {
11097 c = pgetc();
11098 *++p = c;
11099 } while ((unsigned char)(c - '0') <= 7 && --cnt);
11100 pungetc();
11101 } else if (c == 'x') { /* \xHH */
11102 do {
11103 c = pgetc();
11104 *++p = c;
11105 } while (isxdigit(c) && --cnt);
11106 pungetc();
11107 if (cnt == 3) { /* \x but next char is "bad" */
11108 c = 'x';
11109 goto unrecognized;
11110 }
11111 } else { /* simple seq like \\ or \t */
11112 p++;
11113 }
11114 *p = '\0';
11115 p = buf;
11116 c = bb_process_escape_sequence((void*)&p);
11117 } else { /* unrecognized "\z": print both chars unless ' or " */
11118 if (c != '\'' && c != '"') {
11119 unrecognized:
11120 c |= 0x100; /* "please encode \, then me" */
11121 }
11122 }
11123 return c;
11124}
11125#endif
11126
Eric Andersencb57d552001-06-28 07:25:16 +000011127/*
11128 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
11129 * is not NULL, read a here document. In the latter case, eofmark is the
11130 * word which marks the end of the document and striptabs is true if
Denys Vlasenkocd716832009-11-28 22:14:02 +010011131 * leading tabs should be stripped from the document. The argument c
Eric Andersencb57d552001-06-28 07:25:16 +000011132 * is the first character of the input token or document.
11133 *
11134 * Because C does not have internal subroutines, I have simulated them
11135 * using goto's to implement the subroutine linkage. The following macros
11136 * will run code that appears at the end of readtoken1.
11137 */
Eric Andersen2870d962001-07-02 17:27:21 +000011138#define CHECKEND() {goto checkend; checkend_return:;}
11139#define PARSEREDIR() {goto parseredir; parseredir_return:;}
11140#define PARSESUB() {goto parsesub; parsesub_return:;}
11141#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
11142#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
11143#define PARSEARITH() {goto parsearith; parsearith_return:;}
Eric Andersencb57d552001-06-28 07:25:16 +000011144static int
Denys Vlasenkocd716832009-11-28 22:14:02 +010011145readtoken1(int c, int syntax, char *eofmark, int striptabs)
Manuel Novoa III 16815d42001-08-10 19:36:07 +000011146{
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011147 /* NB: syntax parameter fits into smallint */
Denys Vlasenkocd716832009-11-28 22:14:02 +010011148 /* c parameter is an unsigned char or PEOF or PEOA */
Eric Andersencb57d552001-06-28 07:25:16 +000011149 char *out;
11150 int len;
11151 char line[EOFMARKLEN + 1];
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011152 struct nodelist *bqlist;
11153 smallint quotef;
11154 smallint dblquote;
11155 smallint oldstyle;
11156 smallint prevsyntax; /* syntax before arithmetic */
Denis Vlasenko46a53062007-09-24 18:30:02 +000011157#if ENABLE_ASH_EXPAND_PRMT
11158 smallint pssyntax; /* we are expanding a prompt string */
11159#endif
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011160 int varnest; /* levels of variables expansion */
11161 int arinest; /* levels of arithmetic expansion */
11162 int parenlevel; /* levels of parens in arithmetic */
11163 int dqvarnest; /* levels of variables expansion within double quotes */
11164
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011165 IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011166
Eric Andersencb57d552001-06-28 07:25:16 +000011167#if __GNUC__
11168 /* Avoid longjmp clobbering */
11169 (void) &out;
11170 (void) &quotef;
11171 (void) &dblquote;
11172 (void) &varnest;
11173 (void) &arinest;
11174 (void) &parenlevel;
11175 (void) &dqvarnest;
11176 (void) &oldstyle;
11177 (void) &prevsyntax;
11178 (void) &syntax;
11179#endif
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011180 startlinno = g_parsefile->linno;
Eric Andersencb57d552001-06-28 07:25:16 +000011181 bqlist = NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011182 quotef = 0;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011183 prevsyntax = 0;
Denis Vlasenko46a53062007-09-24 18:30:02 +000011184#if ENABLE_ASH_EXPAND_PRMT
11185 pssyntax = (syntax == PSSYNTAX);
11186 if (pssyntax)
11187 syntax = DQSYNTAX;
11188#endif
11189 dblquote = (syntax == DQSYNTAX);
Eric Andersencb57d552001-06-28 07:25:16 +000011190 varnest = 0;
11191 arinest = 0;
11192 parenlevel = 0;
11193 dqvarnest = 0;
11194
11195 STARTSTACKSTR(out);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011196 loop:
11197 /* For each line, until end of word */
Denys Vlasenko958581a2010-09-12 15:04:27 +020011198 CHECKEND(); /* set c to PEOF if at end of here document */
11199 for (;;) { /* until end of line or end of word */
11200 CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
11201 switch (SIT(c, syntax)) {
11202 case CNL: /* '\n' */
11203 if (syntax == BASESYNTAX)
11204 goto endword; /* exit outer loop */
11205 USTPUTC(c, out);
11206 g_parsefile->linno++;
11207 setprompt_if(doprompt, 2);
11208 c = pgetc();
11209 goto loop; /* continue outer loop */
11210 case CWORD:
11211 USTPUTC(c, out);
11212 break;
11213 case CCTL:
11214 if (eofmark == NULL || dblquote)
11215 USTPUTC(CTLESC, out);
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011216#if ENABLE_ASH_BASH_COMPAT
Denys Vlasenko958581a2010-09-12 15:04:27 +020011217 if (c == '\\' && bash_dollar_squote) {
11218 c = decode_dollar_squote();
11219 if (c & 0x100) {
11220 USTPUTC('\\', out);
11221 c = (unsigned char)c;
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011222 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011223 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011224#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011225 USTPUTC(c, out);
11226 break;
11227 case CBACK: /* backslash */
11228 c = pgetc_without_PEOA();
11229 if (c == PEOF) {
11230 USTPUTC(CTLESC, out);
11231 USTPUTC('\\', out);
11232 pungetc();
11233 } else if (c == '\n') {
11234 setprompt_if(doprompt, 2);
11235 } else {
11236#if ENABLE_ASH_EXPAND_PRMT
11237 if (c == '$' && pssyntax) {
Eric Andersenc470f442003-07-28 09:56:35 +000011238 USTPUTC(CTLESC, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011239 USTPUTC('\\', out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011240 }
Denis Vlasenko46a53062007-09-24 18:30:02 +000011241#endif
Denys Vlasenko958581a2010-09-12 15:04:27 +020011242 /* Backslash is retained if we are in "str" and next char isn't special */
11243 if (dblquote
11244 && c != '\\'
11245 && c != '`'
11246 && c != '$'
11247 && (c != '"' || eofmark != NULL)
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011248 ) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011249 USTPUTC(CTLESC, out);
11250 USTPUTC('\\', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011251 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011252 if (SIT(c, SQSYNTAX) == CCTL)
11253 USTPUTC(CTLESC, out);
Denys Vlasenko0ff78a02010-08-30 15:20:07 +020011254 USTPUTC(c, out);
Denys Vlasenko958581a2010-09-12 15:04:27 +020011255 quotef = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000011256 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011257 break;
11258 case CSQUOTE:
11259 syntax = SQSYNTAX;
11260 quotemark:
11261 if (eofmark == NULL) {
11262 USTPUTC(CTLQUOTEMARK, out);
11263 }
11264 break;
11265 case CDQUOTE:
11266 syntax = DQSYNTAX;
11267 dblquote = 1;
11268 goto quotemark;
11269 case CENDQUOTE:
11270 IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
11271 if (eofmark != NULL && arinest == 0
11272 && varnest == 0
11273 ) {
11274 USTPUTC(c, out);
11275 } else {
11276 if (dqvarnest == 0) {
11277 syntax = BASESYNTAX;
11278 dblquote = 0;
11279 }
11280 quotef = 1;
11281 goto quotemark;
11282 }
11283 break;
11284 case CVAR: /* '$' */
11285 PARSESUB(); /* parse substitution */
11286 break;
11287 case CENDVAR: /* '}' */
11288 if (varnest > 0) {
11289 varnest--;
11290 if (dqvarnest > 0) {
11291 dqvarnest--;
11292 }
11293 c = CTLENDVAR;
11294 }
11295 USTPUTC(c, out);
11296 break;
11297#if ENABLE_SH_MATH_SUPPORT
11298 case CLP: /* '(' in arithmetic */
11299 parenlevel++;
11300 USTPUTC(c, out);
11301 break;
11302 case CRP: /* ')' in arithmetic */
11303 if (parenlevel > 0) {
11304 parenlevel--;
11305 } else {
11306 if (pgetc() == ')') {
11307 if (--arinest == 0) {
11308 syntax = prevsyntax;
11309 dblquote = (syntax == DQSYNTAX);
11310 c = CTLENDARI;
11311 }
11312 } else {
11313 /*
11314 * unbalanced parens
11315 * (don't 2nd guess - no error)
11316 */
11317 pungetc();
11318 }
11319 }
11320 USTPUTC(c, out);
11321 break;
11322#endif
11323 case CBQUOTE: /* '`' */
11324 PARSEBACKQOLD();
11325 break;
11326 case CENDFILE:
11327 goto endword; /* exit outer loop */
11328 case CIGN:
11329 break;
11330 default:
11331 if (varnest == 0) {
11332#if ENABLE_ASH_BASH_COMPAT
11333 if (c == '&') {
11334 if (pgetc() == '>')
11335 c = 0x100 + '>'; /* flag &> */
11336 pungetc();
11337 }
11338#endif
11339 goto endword; /* exit outer loop */
11340 }
11341 IF_ASH_ALIAS(if (c != PEOA))
11342 USTPUTC(c, out);
11343 }
11344 c = pgetc_fast();
11345 } /* for (;;) */
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011346 endword:
Denys Vlasenko958581a2010-09-12 15:04:27 +020011347
Mike Frysinger98c52642009-04-02 10:02:37 +000011348#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011349 if (syntax == ARISYNTAX)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011350 raise_error_syntax("missing '))'");
Eric Andersenc470f442003-07-28 09:56:35 +000011351#endif
Denis Vlasenko99eb8502007-02-23 21:09:49 +000011352 if (syntax != BASESYNTAX && !parsebackquote && eofmark == NULL)
Denis Vlasenko559691a2008-10-05 18:39:31 +000011353 raise_error_syntax("unterminated quoted string");
Eric Andersencb57d552001-06-28 07:25:16 +000011354 if (varnest != 0) {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011355 startlinno = g_parsefile->linno;
Eric Andersenc470f442003-07-28 09:56:35 +000011356 /* { */
Denis Vlasenko559691a2008-10-05 18:39:31 +000011357 raise_error_syntax("missing '}'");
Eric Andersencb57d552001-06-28 07:25:16 +000011358 }
11359 USTPUTC('\0', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011360 len = out - (char *)stackblock();
Eric Andersencb57d552001-06-28 07:25:16 +000011361 out = stackblock();
11362 if (eofmark == NULL) {
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011363 if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
Denis Vlasenko834dee72008-10-07 09:18:30 +000011364 && quotef == 0
11365 ) {
Denis Vlasenko559691a2008-10-05 18:39:31 +000011366 if (isdigit_str9(out)) {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011367 PARSEREDIR(); /* passed as params: out, c */
11368 lasttoken = TREDIR;
11369 return lasttoken;
11370 }
11371 /* else: non-number X seen, interpret it
11372 * as "NNNX>file" = "NNNX >file" */
Eric Andersencb57d552001-06-28 07:25:16 +000011373 }
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011374 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011375 }
11376 quoteflag = quotef;
11377 backquotelist = bqlist;
11378 grabstackblock(len);
11379 wordtext = out;
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011380 lasttoken = TWORD;
11381 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011382/* end of readtoken routine */
11383
Eric Andersencb57d552001-06-28 07:25:16 +000011384/*
11385 * Check to see whether we are at the end of the here document. When this
11386 * is called, c is set to the first character of the next input line. If
11387 * we are at the end of the here document, this routine sets the c to PEOF.
11388 */
Eric Andersenc470f442003-07-28 09:56:35 +000011389checkend: {
11390 if (eofmark) {
Denis Vlasenko131ae172007-02-18 13:00:19 +000011391#if ENABLE_ASH_ALIAS
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011392 if (c == PEOA)
11393 c = pgetc_without_PEOA();
Eric Andersenc470f442003-07-28 09:56:35 +000011394#endif
11395 if (striptabs) {
11396 while (c == '\t') {
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011397 c = pgetc_without_PEOA();
Eric Andersencb57d552001-06-28 07:25:16 +000011398 }
Eric Andersenc470f442003-07-28 09:56:35 +000011399 }
11400 if (c == *eofmark) {
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011401 if (pfgets(line, sizeof(line)) != NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000011402 char *p, *q;
Eric Andersencb57d552001-06-28 07:25:16 +000011403
Eric Andersenc470f442003-07-28 09:56:35 +000011404 p = line;
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011405 for (q = eofmark + 1; *q && *p == *q; p++, q++)
11406 continue;
Eric Andersenc470f442003-07-28 09:56:35 +000011407 if (*p == '\n' && *q == '\0') {
11408 c = PEOF;
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011409 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011410 needprompt = doprompt;
11411 } else {
11412 pushstring(line, NULL);
Eric Andersencb57d552001-06-28 07:25:16 +000011413 }
11414 }
11415 }
11416 }
Eric Andersenc470f442003-07-28 09:56:35 +000011417 goto checkend_return;
11418}
Eric Andersencb57d552001-06-28 07:25:16 +000011419
Eric Andersencb57d552001-06-28 07:25:16 +000011420/*
11421 * Parse a redirection operator. The variable "out" points to a string
11422 * specifying the fd to be redirected. The variable "c" contains the
11423 * first character of the redirection operator.
11424 */
Eric Andersenc470f442003-07-28 09:56:35 +000011425parseredir: {
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011426 /* out is already checked to be a valid number or "" */
11427 int fd = (*out == '\0' ? -1 : atoi(out));
Eric Andersenc470f442003-07-28 09:56:35 +000011428 union node *np;
Eric Andersencb57d552001-06-28 07:25:16 +000011429
Denis Vlasenko597906c2008-02-20 16:38:54 +000011430 np = stzalloc(sizeof(struct nfile));
Eric Andersenc470f442003-07-28 09:56:35 +000011431 if (c == '>') {
11432 np->nfile.fd = 1;
11433 c = pgetc();
11434 if (c == '>')
11435 np->type = NAPPEND;
11436 else if (c == '|')
11437 np->type = NCLOBBER;
11438 else if (c == '&')
11439 np->type = NTOFD;
Denis Vlasenko559691a2008-10-05 18:39:31 +000011440 /* it also can be NTO2 (>&file), but we can't figure it out yet */
Eric Andersenc470f442003-07-28 09:56:35 +000011441 else {
11442 np->type = NTO;
11443 pungetc();
Eric Andersencb57d552001-06-28 07:25:16 +000011444 }
Denis Vlasenko834dee72008-10-07 09:18:30 +000011445 }
11446#if ENABLE_ASH_BASH_COMPAT
11447 else if (c == 0x100 + '>') { /* this flags &> redirection */
11448 np->nfile.fd = 1;
11449 pgetc(); /* this is '>', no need to check */
11450 np->type = NTO2;
11451 }
11452#endif
11453 else { /* c == '<' */
Denis Vlasenko597906c2008-02-20 16:38:54 +000011454 /*np->nfile.fd = 0; - stzalloc did it */
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011455 c = pgetc();
11456 switch (c) {
Eric Andersenc470f442003-07-28 09:56:35 +000011457 case '<':
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011458 if (sizeof(struct nfile) != sizeof(struct nhere)) {
Denis Vlasenko597906c2008-02-20 16:38:54 +000011459 np = stzalloc(sizeof(struct nhere));
11460 /*np->nfile.fd = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011461 }
11462 np->type = NHERE;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011463 heredoc = stzalloc(sizeof(struct heredoc));
Eric Andersenc470f442003-07-28 09:56:35 +000011464 heredoc->here = np;
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011465 c = pgetc();
11466 if (c == '-') {
Eric Andersenc470f442003-07-28 09:56:35 +000011467 heredoc->striptabs = 1;
11468 } else {
Denis Vlasenko838ffd52008-02-21 04:32:08 +000011469 /*heredoc->striptabs = 0; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011470 pungetc();
11471 }
11472 break;
11473
11474 case '&':
11475 np->type = NFROMFD;
11476 break;
11477
11478 case '>':
11479 np->type = NFROMTO;
11480 break;
11481
11482 default:
11483 np->type = NFROM;
11484 pungetc();
11485 break;
11486 }
Eric Andersencb57d552001-06-28 07:25:16 +000011487 }
Denis Vlasenko6fbb43b2008-07-24 19:44:41 +000011488 if (fd >= 0)
11489 np->nfile.fd = fd;
Eric Andersenc470f442003-07-28 09:56:35 +000011490 redirnode = np;
11491 goto parseredir_return;
11492}
Eric Andersencb57d552001-06-28 07:25:16 +000011493
Eric Andersencb57d552001-06-28 07:25:16 +000011494/*
11495 * Parse a substitution. At this point, we have read the dollar sign
11496 * and nothing else.
11497 */
Denis Vlasenkocc571512007-02-23 21:10:35 +000011498
11499/* is_special(c) evaluates to 1 for c in "!#$*-0123456789?@"; 0 otherwise
11500 * (assuming ascii char codes, as the original implementation did) */
11501#define is_special(c) \
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011502 (((unsigned)(c) - 33 < 32) \
11503 && ((0xc1ff920dU >> ((unsigned)(c) - 33)) & 1))
Eric Andersenc470f442003-07-28 09:56:35 +000011504parsesub: {
Denys Vlasenkocd716832009-11-28 22:14:02 +010011505 unsigned char subtype;
Eric Andersenc470f442003-07-28 09:56:35 +000011506 int typeloc;
11507 int flags;
Eric Andersencb57d552001-06-28 07:25:16 +000011508
Eric Andersenc470f442003-07-28 09:56:35 +000011509 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011510 if (c > 255 /* PEOA or PEOF */
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011511 || (c != '(' && c != '{' && !is_name(c) && !is_special(c))
Eric Andersenc470f442003-07-28 09:56:35 +000011512 ) {
Denis Vlasenkoef527f52008-06-23 01:52:30 +000011513#if ENABLE_ASH_BASH_COMPAT
11514 if (c == '\'')
11515 bash_dollar_squote = 1;
11516 else
11517#endif
11518 USTPUTC('$', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011519 pungetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011520 } else if (c == '(') {
11521 /* $(command) or $((arith)) */
Eric Andersenc470f442003-07-28 09:56:35 +000011522 if (pgetc() == '(') {
Mike Frysinger98c52642009-04-02 10:02:37 +000011523#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000011524 PARSEARITH();
11525#else
Mike Frysinger98a6f562008-06-09 09:38:45 +000011526 raise_error_syntax("you disabled math support for $((arith)) syntax");
Eric Andersenc470f442003-07-28 09:56:35 +000011527#endif
Glenn L McGrath9fef17d2002-08-22 18:41:20 +000011528 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011529 pungetc();
11530 PARSEBACKQNEW();
11531 }
11532 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011533 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
Eric Andersenc470f442003-07-28 09:56:35 +000011534 USTPUTC(CTLVAR, out);
11535 typeloc = out - (char *)stackblock();
11536 USTPUTC(VSNORMAL, out);
11537 subtype = VSNORMAL;
11538 if (c == '{') {
11539 c = pgetc();
11540 if (c == '#') {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011541 c = pgetc();
11542 if (c == '}')
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011543 c = '#'; /* ${#} - same as $# */
Eric Andersenc470f442003-07-28 09:56:35 +000011544 else
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011545 subtype = VSLENGTH; /* ${#VAR} */
11546 } else {
Eric Andersenc470f442003-07-28 09:56:35 +000011547 subtype = 0;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011548 }
Eric Andersenc470f442003-07-28 09:56:35 +000011549 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011550 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011551 /* $[{[#]]NAME[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011552 do {
11553 STPUTC(c, out);
Eric Andersencb57d552001-06-28 07:25:16 +000011554 c = pgetc();
Denys Vlasenkocd716832009-11-28 22:14:02 +010011555 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011556 } else if (isdigit(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011557 /* $[{[#]]NUM[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011558 do {
11559 STPUTC(c, out);
11560 c = pgetc();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011561 } while (isdigit(c));
Denis Vlasenkoa0f82e92007-02-18 12:35:30 +000011562 } else if (is_special(c)) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011563 /* $[{[#]]<specialchar>[}] */
Eric Andersenc470f442003-07-28 09:56:35 +000011564 USTPUTC(c, out);
11565 c = pgetc();
Denis Vlasenko559691a2008-10-05 18:39:31 +000011566 } else {
11567 badsub:
11568 raise_error_syntax("bad substitution");
11569 }
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011570 if (c != '}' && subtype == VSLENGTH) {
11571 /* ${#VAR didn't end with } */
Cristian Ionescu-Idbohrn301f5ec2009-10-05 02:07:23 +020011572 goto badsub;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011573 }
Eric Andersencb57d552001-06-28 07:25:16 +000011574
Eric Andersenc470f442003-07-28 09:56:35 +000011575 STPUTC('=', out);
11576 flags = 0;
11577 if (subtype == 0) {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011578 /* ${VAR...} but not $VAR or ${#VAR} */
11579 /* c == first char after VAR */
Eric Andersenc470f442003-07-28 09:56:35 +000011580 switch (c) {
11581 case ':':
Eric Andersenc470f442003-07-28 09:56:35 +000011582 c = pgetc();
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011583#if ENABLE_ASH_BASH_COMPAT
11584 if (c == ':' || c == '$' || isdigit(c)) {
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011585//TODO: support more general format ${v:EXPR:EXPR},
11586// where EXPR follows $(()) rules
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011587 subtype = VSSUBSTR;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011588 pungetc();
11589 break; /* "goto do_pungetc" is bigger (!) */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011590 }
11591#endif
11592 flags = VSNUL;
Eric Andersenc470f442003-07-28 09:56:35 +000011593 /*FALLTHROUGH*/
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011594 default: {
11595 static const char types[] ALIGN1 = "}-+?=";
11596 const char *p = strchr(types, c);
Eric Andersenc470f442003-07-28 09:56:35 +000011597 if (p == NULL)
11598 goto badsub;
11599 subtype = p - types + VSNORMAL;
11600 break;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011601 }
Eric Andersenc470f442003-07-28 09:56:35 +000011602 case '%':
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011603 case '#': {
11604 int cc = c;
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011605 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011606 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011607 if (c != cc)
11608 goto do_pungetc;
11609 subtype++;
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011610 break;
11611 }
11612#if ENABLE_ASH_BASH_COMPAT
11613 case '/':
Denys Vlasenko6040fe82010-09-12 15:03:16 +020011614 /* ${v/[/]pattern/repl} */
11615//TODO: encode pattern and repl separately.
11616// Currently ${v/$var_with_slash/repl} is horribly broken
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011617 subtype = VSREPLACE;
11618 c = pgetc();
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011619 if (c != '/')
11620 goto do_pungetc;
11621 subtype++; /* VSREPLACEALL */
Denis Vlasenko92e13c22008-03-25 01:17:40 +000011622 break;
11623#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011624 }
Eric Andersenc470f442003-07-28 09:56:35 +000011625 } else {
Denys Vlasenkob0fbe4b2010-08-05 17:19:27 +020011626 do_pungetc:
Eric Andersenc470f442003-07-28 09:56:35 +000011627 pungetc();
11628 }
11629 if (dblquote || arinest)
11630 flags |= VSQUOTE;
Denys Vlasenkocd716832009-11-28 22:14:02 +010011631 ((unsigned char *)stackblock())[typeloc] = subtype | flags;
Eric Andersenc470f442003-07-28 09:56:35 +000011632 if (subtype != VSNORMAL) {
11633 varnest++;
11634 if (dblquote || arinest) {
11635 dqvarnest++;
Eric Andersencb57d552001-06-28 07:25:16 +000011636 }
11637 }
11638 }
Eric Andersenc470f442003-07-28 09:56:35 +000011639 goto parsesub_return;
11640}
Eric Andersencb57d552001-06-28 07:25:16 +000011641
Eric Andersencb57d552001-06-28 07:25:16 +000011642/*
11643 * Called to parse command substitutions. Newstyle is set if the command
11644 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
11645 * list of commands (passed by reference), and savelen is the number of
11646 * characters on the top of the stack which must be preserved.
11647 */
Eric Andersenc470f442003-07-28 09:56:35 +000011648parsebackq: {
11649 struct nodelist **nlpp;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011650 smallint savepbq;
Eric Andersenc470f442003-07-28 09:56:35 +000011651 union node *n;
11652 char *volatile str;
11653 struct jmploc jmploc;
11654 struct jmploc *volatile savehandler;
11655 size_t savelen;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011656 smallint saveprompt = 0;
11657
Eric Andersencb57d552001-06-28 07:25:16 +000011658#ifdef __GNUC__
Eric Andersenc470f442003-07-28 09:56:35 +000011659 (void) &saveprompt;
Eric Andersencb57d552001-06-28 07:25:16 +000011660#endif
Eric Andersenc470f442003-07-28 09:56:35 +000011661 savepbq = parsebackquote;
11662 if (setjmp(jmploc.loc)) {
Denis Vlasenko60818682007-09-28 22:07:23 +000011663 free(str);
Eric Andersenc470f442003-07-28 09:56:35 +000011664 parsebackquote = 0;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011665 exception_handler = savehandler;
11666 longjmp(exception_handler->loc, 1);
Eric Andersenc470f442003-07-28 09:56:35 +000011667 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000011668 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000011669 str = NULL;
11670 savelen = out - (char *)stackblock();
11671 if (savelen > 0) {
11672 str = ckmalloc(savelen);
11673 memcpy(str, stackblock(), savelen);
11674 }
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011675 savehandler = exception_handler;
11676 exception_handler = &jmploc;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011677 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000011678 if (oldstyle) {
11679 /* We must read until the closing backquote, giving special
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010011680 * treatment to some slashes, and then push the string and
11681 * reread it as input, interpreting it normally.
11682 */
Eric Andersenc470f442003-07-28 09:56:35 +000011683 char *pout;
Eric Andersenc470f442003-07-28 09:56:35 +000011684 size_t psavelen;
11685 char *pstr;
11686
Eric Andersenc470f442003-07-28 09:56:35 +000011687 STARTSTACKSTR(pout);
11688 for (;;) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020011689 int pc;
11690
11691 setprompt_if(needprompt, 2);
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011692 pc = pgetc();
11693 switch (pc) {
Eric Andersenc470f442003-07-28 09:56:35 +000011694 case '`':
11695 goto done;
11696
11697 case '\\':
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011698 pc = pgetc();
11699 if (pc == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011700 g_parsefile->linno++;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011701 setprompt_if(doprompt, 2);
Eric Andersenc470f442003-07-28 09:56:35 +000011702 /*
11703 * If eating a newline, avoid putting
11704 * the newline into the new character
11705 * stream (via the STPUTC after the
11706 * switch).
11707 */
11708 continue;
11709 }
11710 if (pc != '\\' && pc != '`' && pc != '$'
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011711 && (!dblquote || pc != '"')
11712 ) {
Eric Andersenc470f442003-07-28 09:56:35 +000011713 STPUTC('\\', pout);
Denys Vlasenko76bc2d62009-11-29 01:37:46 +010011714 }
Denys Vlasenkocd716832009-11-28 22:14:02 +010011715 if (pc <= 255 /* not PEOA or PEOF */) {
Eric Andersenc470f442003-07-28 09:56:35 +000011716 break;
11717 }
11718 /* fall through */
11719
11720 case PEOF:
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011721 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011722 startlinno = g_parsefile->linno;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011723 raise_error_syntax("EOF in backquote substitution");
Eric Andersenc470f442003-07-28 09:56:35 +000011724
11725 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011726 g_parsefile->linno++;
Eric Andersenc470f442003-07-28 09:56:35 +000011727 needprompt = doprompt;
11728 break;
11729
11730 default:
11731 break;
11732 }
11733 STPUTC(pc, pout);
11734 }
Denis Vlasenko5cedb752007-02-18 19:56:41 +000011735 done:
Eric Andersenc470f442003-07-28 09:56:35 +000011736 STPUTC('\0', pout);
11737 psavelen = pout - (char *)stackblock();
11738 if (psavelen > 0) {
11739 pstr = grabstackstr(pout);
11740 setinputstring(pstr);
11741 }
11742 }
11743 nlpp = &bqlist;
11744 while (*nlpp)
11745 nlpp = &(*nlpp)->next;
Denis Vlasenko597906c2008-02-20 16:38:54 +000011746 *nlpp = stzalloc(sizeof(**nlpp));
11747 /* (*nlpp)->next = NULL; - stzalloc did it */
Eric Andersenc470f442003-07-28 09:56:35 +000011748 parsebackquote = oldstyle;
11749
11750 if (oldstyle) {
11751 saveprompt = doprompt;
11752 doprompt = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000011753 }
11754
Eric Andersenc470f442003-07-28 09:56:35 +000011755 n = list(2);
11756
11757 if (oldstyle)
11758 doprompt = saveprompt;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011759 else if (readtoken() != TRP)
11760 raise_error_unexpected_syntax(TRP);
Eric Andersenc470f442003-07-28 09:56:35 +000011761
11762 (*nlpp)->n = n;
11763 if (oldstyle) {
11764 /*
11765 * Start reading from old file again, ignoring any pushed back
11766 * tokens left from the backquote parsing
11767 */
11768 popfile();
11769 tokpushback = 0;
11770 }
11771 while (stackblocksize() <= savelen)
11772 growstackblock();
11773 STARTSTACKSTR(out);
11774 if (str) {
11775 memcpy(out, str, savelen);
11776 STADJUST(savelen, out);
Denis Vlasenkob012b102007-02-19 22:43:01 +000011777 INT_OFF;
11778 free(str);
Eric Andersenc470f442003-07-28 09:56:35 +000011779 str = NULL;
Denis Vlasenkob012b102007-02-19 22:43:01 +000011780 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000011781 }
11782 parsebackquote = savepbq;
Denis Vlasenko2da584f2007-02-19 22:44:05 +000011783 exception_handler = savehandler;
Eric Andersenc470f442003-07-28 09:56:35 +000011784 if (arinest || dblquote)
11785 USTPUTC(CTLBACKQ | CTLQUOTE, out);
11786 else
11787 USTPUTC(CTLBACKQ, out);
11788 if (oldstyle)
11789 goto parsebackq_oldreturn;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011790 goto parsebackq_newreturn;
Eric Andersenc470f442003-07-28 09:56:35 +000011791}
11792
Mike Frysinger98c52642009-04-02 10:02:37 +000011793#if ENABLE_SH_MATH_SUPPORT
Eric Andersencb57d552001-06-28 07:25:16 +000011794/*
11795 * Parse an arithmetic expansion (indicate start of one and set state)
11796 */
Eric Andersenc470f442003-07-28 09:56:35 +000011797parsearith: {
Eric Andersenc470f442003-07-28 09:56:35 +000011798 if (++arinest == 1) {
11799 prevsyntax = syntax;
11800 syntax = ARISYNTAX;
11801 USTPUTC(CTLARI, out);
11802 if (dblquote)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011803 USTPUTC('"', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011804 else
Denis Vlasenkoa624c112007-02-19 22:45:43 +000011805 USTPUTC(' ', out);
Eric Andersenc470f442003-07-28 09:56:35 +000011806 } else {
11807 /*
11808 * we collapse embedded arithmetic expansion to
11809 * parenthesis, which should be equivalent
11810 */
11811 USTPUTC('(', out);
Eric Andersencb57d552001-06-28 07:25:16 +000011812 }
Eric Andersenc470f442003-07-28 09:56:35 +000011813 goto parsearith_return;
11814}
11815#endif
Eric Andersencb57d552001-06-28 07:25:16 +000011816
Eric Andersenc470f442003-07-28 09:56:35 +000011817} /* end of readtoken */
11818
Eric Andersencb57d552001-06-28 07:25:16 +000011819/*
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011820 * Read the next input token.
11821 * If the token is a word, we set backquotelist to the list of cmds in
11822 * backquotes. We set quoteflag to true if any part of the word was
11823 * quoted.
11824 * If the token is TREDIR, then we set redirnode to a structure containing
11825 * the redirection.
11826 * In all cases, the variable startlinno is set to the number of the line
11827 * on which the token starts.
11828 *
11829 * [Change comment: here documents and internal procedures]
11830 * [Readtoken shouldn't have any arguments. Perhaps we should make the
11831 * word parsing code into a separate routine. In this case, readtoken
11832 * doesn't need to have any internal procedures, but parseword does.
11833 * We could also make parseoperator in essence the main routine, and
11834 * have parseword (readtoken1?) handle both words and redirection.]
Eric Andersencb57d552001-06-28 07:25:16 +000011835 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011836#define NEW_xxreadtoken
11837#ifdef NEW_xxreadtoken
11838/* singles must be first! */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011839static const char xxreadtoken_chars[7] ALIGN1 = {
Denis Vlasenko834dee72008-10-07 09:18:30 +000011840 '\n', '(', ')', /* singles */
11841 '&', '|', ';', /* doubles */
11842 0
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011843};
Eric Andersencb57d552001-06-28 07:25:16 +000011844
Denis Vlasenko834dee72008-10-07 09:18:30 +000011845#define xxreadtoken_singles 3
11846#define xxreadtoken_doubles 3
11847
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011848static const char xxreadtoken_tokens[] ALIGN1 = {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011849 TNL, TLP, TRP, /* only single occurrence allowed */
11850 TBACKGND, TPIPE, TSEMI, /* if single occurrence */
11851 TEOF, /* corresponds to trailing nul */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000011852 TAND, TOR, TENDCASE /* if double occurrence */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011853};
11854
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011855static int
11856xxreadtoken(void)
11857{
11858 int c;
11859
11860 if (tokpushback) {
11861 tokpushback = 0;
11862 return lasttoken;
Eric Andersencb57d552001-06-28 07:25:16 +000011863 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011864 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011865 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011866 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011867 c = pgetc_fast();
Denis Vlasenko5e34ff22009-04-21 11:09:40 +000011868 if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011869 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011870
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011871 if (c == '#') {
11872 while ((c = pgetc()) != '\n' && c != PEOF)
11873 continue;
11874 pungetc();
11875 } else if (c == '\\') {
11876 if (pgetc() != '\n') {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011877 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011878 break; /* return readtoken1(...) */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011879 }
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011880 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011881 setprompt_if(doprompt, 2);
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011882 } else {
11883 const char *p;
11884
11885 p = xxreadtoken_chars + sizeof(xxreadtoken_chars) - 1;
11886 if (c != PEOF) {
11887 if (c == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011888 g_parsefile->linno++;
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011889 needprompt = doprompt;
11890 }
11891
11892 p = strchr(xxreadtoken_chars, c);
Denis Vlasenko834dee72008-10-07 09:18:30 +000011893 if (p == NULL)
11894 break; /* return readtoken1(...) */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011895
Denis Vlasenko834dee72008-10-07 09:18:30 +000011896 if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) {
11897 int cc = pgetc();
11898 if (cc == c) { /* double occurrence? */
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011899 p += xxreadtoken_doubles + 1;
11900 } else {
11901 pungetc();
Denis Vlasenko834dee72008-10-07 09:18:30 +000011902#if ENABLE_ASH_BASH_COMPAT
11903 if (c == '&' && cc == '>') /* &> */
11904 break; /* return readtoken1(...) */
11905#endif
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011906 }
11907 }
11908 }
11909 lasttoken = xxreadtoken_tokens[p - xxreadtoken_chars];
11910 return lasttoken;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011911 }
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011912 } /* for (;;) */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011913
11914 return readtoken1(c, BASESYNTAX, (char *) NULL, 0);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011915}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011916#else /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011917#define RETURN(token) return lasttoken = token
11918static int
11919xxreadtoken(void)
11920{
11921 int c;
11922
11923 if (tokpushback) {
11924 tokpushback = 0;
11925 return lasttoken;
11926 }
Denys Vlasenko958581a2010-09-12 15:04:27 +020011927 setprompt_if(needprompt, 2);
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011928 startlinno = g_parsefile->linno;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011929 for (;;) { /* until token or start of word found */
Denis Vlasenko834dee72008-10-07 09:18:30 +000011930 c = pgetc_fast();
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011931 switch (c) {
11932 case ' ': case '\t':
Denys Vlasenko2ce42e92009-11-29 02:18:13 +010011933 IF_ASH_ALIAS(case PEOA:)
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011934 continue;
11935 case '#':
Denis Vlasenkof7d56652008-03-25 05:51:41 +000011936 while ((c = pgetc()) != '\n' && c != PEOF)
11937 continue;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011938 pungetc();
11939 continue;
11940 case '\\':
11941 if (pgetc() == '\n') {
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011942 startlinno = ++g_parsefile->linno;
Denys Vlasenko958581a2010-09-12 15:04:27 +020011943 setprompt_if(doprompt, 2);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011944 continue;
11945 }
11946 pungetc();
11947 goto breakloop;
11948 case '\n':
Denis Vlasenko41eb3002008-11-28 03:42:31 +000011949 g_parsefile->linno++;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011950 needprompt = doprompt;
11951 RETURN(TNL);
11952 case PEOF:
11953 RETURN(TEOF);
11954 case '&':
11955 if (pgetc() == '&')
11956 RETURN(TAND);
11957 pungetc();
11958 RETURN(TBACKGND);
11959 case '|':
11960 if (pgetc() == '|')
11961 RETURN(TOR);
11962 pungetc();
11963 RETURN(TPIPE);
11964 case ';':
11965 if (pgetc() == ';')
11966 RETURN(TENDCASE);
11967 pungetc();
11968 RETURN(TSEMI);
11969 case '(':
11970 RETURN(TLP);
11971 case ')':
11972 RETURN(TRP);
11973 default:
11974 goto breakloop;
11975 }
11976 }
11977 breakloop:
11978 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
11979#undef RETURN
11980}
Denis Vlasenko176d49d2008-10-06 09:51:47 +000011981#endif /* old xxreadtoken */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011982
11983static int
11984readtoken(void)
11985{
11986 int t;
11987#if DEBUG
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000011988 smallint alreadyseen = tokpushback;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000011989#endif
11990
11991#if ENABLE_ASH_ALIAS
11992 top:
11993#endif
11994
11995 t = xxreadtoken();
11996
11997 /*
11998 * eat newlines
11999 */
12000 if (checkkwd & CHKNL) {
12001 while (t == TNL) {
12002 parseheredoc();
12003 t = xxreadtoken();
12004 }
12005 }
12006
12007 if (t != TWORD || quoteflag) {
12008 goto out;
12009 }
12010
12011 /*
12012 * check for keywords
12013 */
12014 if (checkkwd & CHKKWD) {
12015 const char *const *pp;
12016
12017 pp = findkwd(wordtext);
12018 if (pp) {
12019 lasttoken = t = pp - tokname_array;
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012020 TRACE(("keyword '%s' recognized\n", tokname_array[t] + 1));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012021 goto out;
12022 }
12023 }
12024
12025 if (checkkwd & CHKALIAS) {
12026#if ENABLE_ASH_ALIAS
12027 struct alias *ap;
12028 ap = lookupalias(wordtext, 1);
12029 if (ap != NULL) {
12030 if (*ap->val) {
12031 pushstring(ap->val, ap);
12032 }
12033 goto top;
12034 }
12035#endif
12036 }
12037 out:
12038 checkkwd = 0;
12039#if DEBUG
12040 if (!alreadyseen)
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012041 TRACE(("token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012042 else
Denys Vlasenkoa0ec4f52010-05-20 12:50:42 +020012043 TRACE(("reread token '%s' %s\n", tokname_array[t] + 1, t == TWORD ? wordtext : ""));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012044#endif
12045 return t;
Eric Andersencb57d552001-06-28 07:25:16 +000012046}
12047
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012048static char
12049peektoken(void)
12050{
12051 int t;
12052
12053 t = readtoken();
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012054 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012055 return tokname_array[t][0];
12056}
Eric Andersencb57d552001-06-28 07:25:16 +000012057
12058/*
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012059 * Read and parse a command. Returns NODE_EOF on end of file.
12060 * (NULL is a valid parse tree indicating a blank line.)
Eric Andersencb57d552001-06-28 07:25:16 +000012061 */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012062static union node *
12063parsecmd(int interact)
Eric Andersen90898442003-08-06 11:20:52 +000012064{
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012065 int t;
Eric Andersencb57d552001-06-28 07:25:16 +000012066
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012067 tokpushback = 0;
12068 doprompt = interact;
Denys Vlasenko958581a2010-09-12 15:04:27 +020012069 setprompt_if(doprompt, doprompt);
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012070 needprompt = 0;
12071 t = readtoken();
12072 if (t == TEOF)
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012073 return NODE_EOF;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012074 if (t == TNL)
12075 return NULL;
Denis Vlasenkobcceb0c2007-09-21 18:06:20 +000012076 tokpushback = 1;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012077 return list(1);
12078}
12079
12080/*
12081 * Input any here documents.
12082 */
12083static void
12084parseheredoc(void)
12085{
12086 struct heredoc *here;
12087 union node *n;
12088
12089 here = heredoclist;
Denis Vlasenko838ffd52008-02-21 04:32:08 +000012090 heredoclist = NULL;
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012091
12092 while (here) {
Denys Vlasenko958581a2010-09-12 15:04:27 +020012093 setprompt_if(needprompt, 2);
12094 readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX,
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012095 here->eofmark, here->striptabs);
Denis Vlasenko597906c2008-02-20 16:38:54 +000012096 n = stzalloc(sizeof(struct narg));
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012097 n->narg.type = NARG;
Denis Vlasenko597906c2008-02-20 16:38:54 +000012098 /*n->narg.next = NULL; - stzalloc did it */
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012099 n->narg.text = wordtext;
12100 n->narg.backquote = backquotelist;
12101 here->here->nhere.doc = n;
12102 here = here->next;
Eric Andersencb57d552001-06-28 07:25:16 +000012103 }
Eric Andersencb57d552001-06-28 07:25:16 +000012104}
12105
12106
12107/*
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012108 * called by editline -- any expansions to the prompt should be added here.
Eric Andersencb57d552001-06-28 07:25:16 +000012109 */
Denis Vlasenko131ae172007-02-18 13:00:19 +000012110#if ENABLE_ASH_EXPAND_PRMT
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012111static const char *
12112expandstr(const char *ps)
12113{
12114 union node n;
12115
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000012116 /* XXX Fix (char *) cast. It _is_ a bug. ps is variable's value,
12117 * and token processing _can_ alter it (delete NULs etc). */
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012118 setinputstring((char *)ps);
Denis Vlasenko46a53062007-09-24 18:30:02 +000012119 readtoken1(pgetc(), PSSYNTAX, nullstr, 0);
"Vladimir N. Oleynik"bef14d72005-09-05 13:25:11 +000012120 popfile();
12121
12122 n.narg.type = NARG;
12123 n.narg.next = NULL;
12124 n.narg.text = wordtext;
12125 n.narg.backquote = backquotelist;
12126
12127 expandarg(&n, NULL, 0);
12128 return stackblock();
12129}
12130#endif
12131
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012132/*
12133 * Execute a command or commands contained in a string.
12134 */
12135static int
12136evalstring(char *s, int mask)
Eric Andersenc470f442003-07-28 09:56:35 +000012137{
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012138 union node *n;
12139 struct stackmark smark;
12140 int skip;
12141
12142 setinputstring(s);
12143 setstackmark(&smark);
12144
12145 skip = 0;
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012146 while ((n = parsecmd(0)) != NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012147 evaltree(n, 0);
12148 popstackmark(&smark);
12149 skip = evalskip;
12150 if (skip)
12151 break;
12152 }
12153 popfile();
12154
12155 skip &= mask;
12156 evalskip = skip;
12157 return skip;
Eric Andersenc470f442003-07-28 09:56:35 +000012158}
12159
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012160/*
12161 * The eval command.
12162 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012163static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012164evalcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012165{
12166 char *p;
12167 char *concat;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012168
Denis Vlasenko68404f12008-03-17 09:00:54 +000012169 if (argv[1]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012170 p = argv[1];
Denis Vlasenko68404f12008-03-17 09:00:54 +000012171 argv += 2;
12172 if (argv[0]) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012173 STARTSTACKSTR(concat);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012174 for (;;) {
12175 concat = stack_putstr(p, concat);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012176 p = *argv++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012177 if (p == NULL)
12178 break;
12179 STPUTC(' ', concat);
12180 }
12181 STPUTC('\0', concat);
12182 p = grabstackstr(concat);
12183 }
12184 evalstring(p, ~SKIPEVAL);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012185 }
12186 return exitstatus;
12187}
12188
12189/*
Denys Vlasenko285ad152009-12-04 23:02:27 +010012190 * Read and execute commands.
12191 * "Top" is nonzero for the top level command loop;
12192 * it turns on prompting if the shell is interactive.
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012193 */
12194static int
12195cmdloop(int top)
12196{
12197 union node *n;
12198 struct stackmark smark;
12199 int inter;
12200 int numeof = 0;
12201
12202 TRACE(("cmdloop(%d) called\n", top));
12203 for (;;) {
12204 int skip;
12205
12206 setstackmark(&smark);
12207#if JOBS
Denis Vlasenkob07a4962008-06-22 13:16:23 +000012208 if (doing_jobctl)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012209 showjobs(stderr, SHOW_CHANGED);
12210#endif
12211 inter = 0;
12212 if (iflag && top) {
12213 inter++;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012214 chkmail();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012215 }
12216 n = parsecmd(inter);
Denys Vlasenko7cee00e2009-07-24 01:08:03 +020012217#if DEBUG
12218 if (DEBUG > 2 && debug && (n != NODE_EOF))
Denys Vlasenko883cea42009-07-11 15:31:59 +020012219 showtree(n);
Denis Vlasenko135cecb2009-04-12 00:00:57 +000012220#endif
Denys Vlasenko86e83ec2009-07-23 22:07:07 +020012221 if (n == NODE_EOF) {
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012222 if (!top || numeof >= 50)
12223 break;
12224 if (!stoppedjobs()) {
12225 if (!Iflag)
12226 break;
12227 out2str("\nUse \"exit\" to leave shell.\n");
12228 }
12229 numeof++;
12230 } else if (nflag == 0) {
Denis Vlasenkofcfaf2e2007-07-14 18:45:37 +000012231 /* job_warning can only be 2,1,0. Here 2->1, 1/0->0 */
12232 job_warning >>= 1;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012233 numeof = 0;
12234 evaltree(n, 0);
12235 }
12236 popstackmark(&smark);
12237 skip = evalskip;
12238
12239 if (skip) {
12240 evalskip = 0;
12241 return skip & SKIPEVAL;
12242 }
12243 }
12244 return 0;
12245}
12246
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012247/*
12248 * Take commands from a file. To be compatible we should do a path
12249 * search for the file, which is necessary to find sub-commands.
12250 */
12251static char *
12252find_dot_file(char *name)
12253{
12254 char *fullname;
12255 const char *path = pathval();
12256 struct stat statb;
12257
12258 /* don't try this for absolute or relative paths */
12259 if (strchr(name, '/'))
12260 return name;
12261
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012262 /* IIRC standards do not say whether . is to be searched.
12263 * And it is even smaller this way, making it unconditional for now:
12264 */
12265 if (1) { /* ENABLE_ASH_BASH_COMPAT */
12266 fullname = name;
12267 goto try_cur_dir;
12268 }
12269
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012270 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenko8ad78e12009-02-15 12:40:30 +000012271 try_cur_dir:
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012272 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
12273 /*
12274 * Don't bother freeing here, since it will
12275 * be freed by the caller.
12276 */
12277 return fullname;
12278 }
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012279 if (fullname != name)
12280 stunalloc(fullname);
Denis Vlasenko0dec6de2007-02-23 21:10:47 +000012281 }
12282
12283 /* not found in the PATH */
12284 ash_msg_and_raise_error("%s: not found", name);
12285 /* NOTREACHED */
12286}
12287
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012288static int FAST_FUNC
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012289dotcmd(int argc, char **argv)
12290{
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012291 char *fullname;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012292 struct strlist *sp;
12293 volatile struct shparam saveparam;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012294
12295 for (sp = cmdenviron; sp; sp = sp->next)
Denis Vlasenko4222ae42007-02-25 02:37:49 +000012296 setvareq(ckstrdup(sp->text), VSTRFIXED | VTEXTFIXED);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012297
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012298 if (!argv[1]) {
12299 /* bash says: "bash: .: filename argument required" */
12300 return 2; /* bash compat */
12301 }
12302
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012303 /* "false; . empty_file; echo $?" should print 0, not 1: */
12304 exitstatus = 0;
12305
Denys Vlasenko091f8312013-03-17 14:25:22 +010012306 /* This aborts if file isn't found, which is POSIXly correct.
12307 * bash returns exitcode 1 instead.
12308 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012309 fullname = find_dot_file(argv[1]);
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012310 argv += 2;
12311 argc -= 2;
12312 if (argc) { /* argc > 0, argv[0] != NULL */
12313 saveparam = shellparam;
12314 shellparam.malloced = 0;
12315 shellparam.nparam = argc;
12316 shellparam.p = argv;
12317 };
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012318
Denys Vlasenko091f8312013-03-17 14:25:22 +010012319 /* This aborts if file can't be opened, which is POSIXly correct.
12320 * bash returns exitcode 1 instead.
12321 */
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012322 setinputfile(fullname, INPUT_PUSH_FILE);
12323 commandname = fullname;
12324 cmdloop(0);
12325 popfile();
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012326
Denys Vlasenkoe66cf822010-05-18 09:12:53 +020012327 if (argc) {
12328 freeparam(&shellparam);
12329 shellparam = saveparam;
12330 };
12331
Denys Vlasenkocd10dc42010-05-17 17:10:46 +020012332 return exitstatus;
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012333}
12334
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012335static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012336exitcmd(int argc UNUSED_PARAM, char **argv)
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012337{
12338 if (stoppedjobs())
12339 return 0;
Denis Vlasenko68404f12008-03-17 09:00:54 +000012340 if (argv[1])
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012341 exitstatus = number(argv[1]);
12342 raise_exception(EXEXIT);
12343 /* NOTREACHED */
12344}
12345
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012346/*
12347 * Read a file containing shell functions.
12348 */
12349static void
12350readcmdfile(char *name)
12351{
12352 setinputfile(name, INPUT_PUSH_FILE);
12353 cmdloop(0);
12354 popfile();
12355}
12356
12357
Denis Vlasenkocc571512007-02-23 21:10:35 +000012358/* ============ find_command inplementation */
12359
12360/*
12361 * Resolve a command name. If you change this routine, you may have to
12362 * change the shellexec routine as well.
12363 */
12364static void
12365find_command(char *name, struct cmdentry *entry, int act, const char *path)
12366{
12367 struct tblentry *cmdp;
12368 int idx;
12369 int prev;
12370 char *fullname;
12371 struct stat statb;
12372 int e;
12373 int updatetbl;
12374 struct builtincmd *bcmd;
12375
12376 /* If name contains a slash, don't use PATH or hash table */
12377 if (strchr(name, '/') != NULL) {
12378 entry->u.index = -1;
12379 if (act & DO_ABS) {
12380 while (stat(name, &statb) < 0) {
12381#ifdef SYSV
12382 if (errno == EINTR)
12383 continue;
12384#endif
12385 entry->cmdtype = CMDUNKNOWN;
12386 return;
12387 }
12388 }
12389 entry->cmdtype = CMDNORMAL;
12390 return;
12391 }
12392
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012393/* #if ENABLE_FEATURE_SH_STANDALONE... moved after builtin check */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012394
12395 updatetbl = (path == pathval());
12396 if (!updatetbl) {
12397 act |= DO_ALTPATH;
12398 if (strstr(path, "%builtin") != NULL)
12399 act |= DO_ALTBLTIN;
12400 }
12401
12402 /* If name is in the table, check answer will be ok */
12403 cmdp = cmdlookup(name, 0);
12404 if (cmdp != NULL) {
12405 int bit;
12406
12407 switch (cmdp->cmdtype) {
12408 default:
12409#if DEBUG
12410 abort();
12411#endif
12412 case CMDNORMAL:
12413 bit = DO_ALTPATH;
12414 break;
12415 case CMDFUNCTION:
12416 bit = DO_NOFUNC;
12417 break;
12418 case CMDBUILTIN:
12419 bit = DO_ALTBLTIN;
12420 break;
12421 }
12422 if (act & bit) {
12423 updatetbl = 0;
12424 cmdp = NULL;
12425 } else if (cmdp->rehash == 0)
12426 /* if not invalidated by cd, we're done */
12427 goto success;
12428 }
12429
12430 /* If %builtin not in path, check for builtin next */
12431 bcmd = find_builtin(name);
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012432 if (bcmd) {
12433 if (IS_BUILTIN_REGULAR(bcmd))
12434 goto builtin_success;
12435 if (act & DO_ALTPATH) {
12436 if (!(act & DO_ALTBLTIN))
12437 goto builtin_success;
12438 } else if (builtinloc <= 0) {
12439 goto builtin_success;
Denis Vlasenko8e858e22007-03-07 09:35:43 +000012440 }
Denis Vlasenkof98dc4d2007-02-23 21:11:02 +000012441 }
Denis Vlasenkocc571512007-02-23 21:10:35 +000012442
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012443#if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko7465dbc2008-04-13 02:25:53 +000012444 {
12445 int applet_no = find_applet_by_name(name);
12446 if (applet_no >= 0) {
12447 entry->cmdtype = CMDNORMAL;
12448 entry->u.index = -2 - applet_no;
12449 return;
12450 }
Denis Vlasenkof20de5b2007-04-29 23:42:54 +000012451 }
12452#endif
12453
Denis Vlasenkocc571512007-02-23 21:10:35 +000012454 /* We have to search path. */
12455 prev = -1; /* where to start */
12456 if (cmdp && cmdp->rehash) { /* doing a rehash */
12457 if (cmdp->cmdtype == CMDBUILTIN)
12458 prev = builtinloc;
12459 else
12460 prev = cmdp->param.index;
12461 }
12462
12463 e = ENOENT;
12464 idx = -1;
12465 loop:
Denys Vlasenko82a6fb32009-06-14 19:42:12 +020012466 while ((fullname = path_advance(&path, name)) != NULL) {
Denis Vlasenkocc571512007-02-23 21:10:35 +000012467 stunalloc(fullname);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012468 /* NB: code below will still use fullname
12469 * despite it being "unallocated" */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012470 idx++;
12471 if (pathopt) {
12472 if (prefix(pathopt, "builtin")) {
12473 if (bcmd)
12474 goto builtin_success;
12475 continue;
Denis Vlasenko4a9ca132008-04-12 20:07:08 +000012476 }
12477 if ((act & DO_NOFUNC)
12478 || !prefix(pathopt, "func")
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +020012479 ) { /* ignore unimplemented options */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012480 continue;
12481 }
12482 }
12483 /* if rehash, don't redo absolute path names */
12484 if (fullname[0] == '/' && idx <= prev) {
12485 if (idx < prev)
12486 continue;
12487 TRACE(("searchexec \"%s\": no change\n", name));
12488 goto success;
12489 }
12490 while (stat(fullname, &statb) < 0) {
12491#ifdef SYSV
12492 if (errno == EINTR)
12493 continue;
12494#endif
12495 if (errno != ENOENT && errno != ENOTDIR)
12496 e = errno;
12497 goto loop;
12498 }
12499 e = EACCES; /* if we fail, this will be the error */
12500 if (!S_ISREG(statb.st_mode))
12501 continue;
12502 if (pathopt) { /* this is a %func directory */
12503 stalloc(strlen(fullname) + 1);
Denis Vlasenkodee82b62007-07-29 14:05:27 +000012504 /* NB: stalloc will return space pointed by fullname
12505 * (because we don't have any intervening allocations
12506 * between stunalloc above and this stalloc) */
Denis Vlasenkocc571512007-02-23 21:10:35 +000012507 readcmdfile(fullname);
12508 cmdp = cmdlookup(name, 0);
12509 if (cmdp == NULL || cmdp->cmdtype != CMDFUNCTION)
12510 ash_msg_and_raise_error("%s not defined in %s", name, fullname);
12511 stunalloc(fullname);
12512 goto success;
12513 }
12514 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
12515 if (!updatetbl) {
12516 entry->cmdtype = CMDNORMAL;
12517 entry->u.index = idx;
12518 return;
12519 }
12520 INT_OFF;
12521 cmdp = cmdlookup(name, 1);
12522 cmdp->cmdtype = CMDNORMAL;
12523 cmdp->param.index = idx;
12524 INT_ON;
12525 goto success;
12526 }
12527
12528 /* We failed. If there was an entry for this command, delete it */
12529 if (cmdp && updatetbl)
12530 delete_cmd_entry();
12531 if (act & DO_ERR)
12532 ash_msg("%s: %s", name, errmsg(e, "not found"));
12533 entry->cmdtype = CMDUNKNOWN;
12534 return;
12535
12536 builtin_success:
12537 if (!updatetbl) {
12538 entry->cmdtype = CMDBUILTIN;
12539 entry->u.cmd = bcmd;
12540 return;
12541 }
12542 INT_OFF;
12543 cmdp = cmdlookup(name, 1);
12544 cmdp->cmdtype = CMDBUILTIN;
12545 cmdp->param.cmd = bcmd;
12546 INT_ON;
12547 success:
12548 cmdp->rehash = 0;
12549 entry->cmdtype = cmdp->cmdtype;
12550 entry->u = cmdp->param;
12551}
12552
12553
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012554/* ============ trap.c */
Eric Andersenc470f442003-07-28 09:56:35 +000012555
Eric Andersencb57d552001-06-28 07:25:16 +000012556/*
Eric Andersencb57d552001-06-28 07:25:16 +000012557 * The trap builtin.
12558 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012559static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012560trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012561{
12562 char *action;
12563 char **ap;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012564 int signo, exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012565
Eric Andersenc470f442003-07-28 09:56:35 +000012566 nextopt(nullstr);
12567 ap = argptr;
12568 if (!*ap) {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012569 for (signo = 0; signo < NSIG; signo++) {
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012570 char *tr = trap_ptr[signo];
12571 if (tr) {
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012572 /* note: bash adds "SIG", but only if invoked
12573 * as "bash". If called as "sh", or if set -o posix,
12574 * then it prints short signal names.
12575 * We are printing short names: */
12576 out1fmt("trap -- %s %s\n",
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012577 single_quote(tr),
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012578 get_signame(signo));
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012579 /* trap_ptr != trap only if we are in special-cased `trap` code.
12580 * In this case, we will exit very soon, no need to free(). */
Denys Vlasenkoe74aaf92009-09-27 02:05:45 +020012581 /* if (trap_ptr != trap && tp[0]) */
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012582 /* free(tr); */
Eric Andersencb57d552001-06-28 07:25:16 +000012583 }
12584 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012585 /*
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012586 if (trap_ptr != trap) {
12587 free(trap_ptr);
12588 trap_ptr = trap;
12589 }
Denys Vlasenko726e1a02009-09-25 02:58:20 +020012590 */
Eric Andersencb57d552001-06-28 07:25:16 +000012591 return 0;
12592 }
Denys Vlasenko21d87d42009-09-25 00:06:51 +020012593
Denis Vlasenko4e19a9c2008-07-26 13:45:57 +000012594 action = NULL;
12595 if (ap[1])
Eric Andersencb57d552001-06-28 07:25:16 +000012596 action = *ap++;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012597 exitcode = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012598 while (*ap) {
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012599 signo = get_signum(*ap);
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012600 if (signo < 0) {
12601 /* Mimic bash message exactly */
12602 ash_msg("%s: invalid signal specification", *ap);
12603 exitcode = 1;
12604 goto next;
12605 }
Denis Vlasenkob012b102007-02-19 22:43:01 +000012606 INT_OFF;
Eric Andersencb57d552001-06-28 07:25:16 +000012607 if (action) {
Denis Vlasenko9f739442006-12-16 23:49:13 +000012608 if (LONE_DASH(action))
Eric Andersencb57d552001-06-28 07:25:16 +000012609 action = NULL;
12610 else
Denis Vlasenko0c032a42007-02-23 01:03:40 +000012611 action = ckstrdup(action);
Eric Andersencb57d552001-06-28 07:25:16 +000012612 }
Denis Vlasenko60818682007-09-28 22:07:23 +000012613 free(trap[signo]);
Denys Vlasenko238bf182010-05-18 15:49:07 +020012614 if (action)
12615 may_have_traps = 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012616 trap[signo] = action;
12617 if (signo != 0)
12618 setsignal(signo);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012619 INT_ON;
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012620 next:
Eric Andersencb57d552001-06-28 07:25:16 +000012621 ap++;
12622 }
Denys Vlasenko496d5bf2010-03-26 15:52:24 +010012623 return exitcode;
Eric Andersencb57d552001-06-28 07:25:16 +000012624}
12625
Eric Andersenc470f442003-07-28 09:56:35 +000012626
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012627/* ============ Builtins */
Eric Andersenc470f442003-07-28 09:56:35 +000012628
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012629#if ENABLE_ASH_HELP
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012630static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012631helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012632{
Denis Vlasenko6b06cb82008-05-15 21:30:45 +000012633 unsigned col;
12634 unsigned i;
Eric Andersenc470f442003-07-28 09:56:35 +000012635
Denys Vlasenkod6b05eb2009-06-06 20:59:55 +020012636 out1fmt(
Denis Vlasenko34d4d892009-04-04 20:24:37 +000012637 "Built-in commands:\n"
12638 "------------------\n");
Denis Vlasenkob71c6682007-07-21 15:08:09 +000012639 for (col = 0, i = 0; i < ARRAY_SIZE(builtintab); i++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012640 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '),
Denis Vlasenko52764022007-02-24 13:42:56 +000012641 builtintab[i].name + 1);
Eric Andersenc470f442003-07-28 09:56:35 +000012642 if (col > 60) {
12643 out1fmt("\n");
12644 col = 0;
12645 }
12646 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012647# if ENABLE_FEATURE_SH_STANDALONE
Denis Vlasenko1aa7e472007-11-28 06:49:03 +000012648 {
12649 const char *a = applet_names;
12650 while (*a) {
12651 col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), a);
12652 if (col > 60) {
12653 out1fmt("\n");
12654 col = 0;
12655 }
12656 a += strlen(a) + 1;
Eric Andersenc470f442003-07-28 09:56:35 +000012657 }
12658 }
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012659# endif
Eric Andersenc470f442003-07-28 09:56:35 +000012660 out1fmt("\n\n");
12661 return EXIT_SUCCESS;
12662}
Denys Vlasenko2ec34962014-09-08 16:52:39 +020012663#endif
Eric Andersenc470f442003-07-28 09:56:35 +000012664
Flemming Madsend96ffda2013-04-07 18:47:24 +020012665#if MAX_HISTORY
12666static int FAST_FUNC
12667historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
12668{
12669 show_history(line_input_state);
12670 return EXIT_SUCCESS;
12671}
12672#endif
12673
Eric Andersencb57d552001-06-28 07:25:16 +000012674/*
Eric Andersencb57d552001-06-28 07:25:16 +000012675 * The export and readonly commands.
12676 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012677static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012678exportcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersencb57d552001-06-28 07:25:16 +000012679{
12680 struct var *vp;
12681 char *name;
12682 const char *p;
Eric Andersenc470f442003-07-28 09:56:35 +000012683 char **aptr;
Denys Vlasenkod5275882012-10-01 13:41:17 +020012684 char opt;
12685 int flag;
12686 int flag_off;
Eric Andersencb57d552001-06-28 07:25:16 +000012687
Denys Vlasenkod5275882012-10-01 13:41:17 +020012688 /* "readonly" in bash accepts, but ignores -n.
12689 * We do the same: it saves a conditional in nextopt's param.
12690 */
12691 flag_off = 0;
12692 while ((opt = nextopt("np")) != '\0') {
12693 if (opt == 'n')
12694 flag_off = VEXPORT;
12695 }
12696 flag = VEXPORT;
12697 if (argv[0][0] == 'r') {
12698 flag = VREADONLY;
12699 flag_off = 0; /* readonly ignores -n */
12700 }
12701 flag_off = ~flag_off;
12702
12703 /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */
12704 {
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012705 aptr = argptr;
12706 name = *aptr;
12707 if (name) {
12708 do {
12709 p = strchr(name, '=');
12710 if (p != NULL) {
12711 p++;
12712 } else {
12713 vp = *findvar(hashvar(name), name);
12714 if (vp) {
Denys Vlasenkod5275882012-10-01 13:41:17 +020012715 vp->flags = ((vp->flags | flag) & flag_off);
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012716 continue;
12717 }
Eric Andersencb57d552001-06-28 07:25:16 +000012718 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012719 setvar(name, p, (flag & flag_off));
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012720 } while ((name = *++aptr) != NULL);
12721 return 0;
12722 }
Eric Andersencb57d552001-06-28 07:25:16 +000012723 }
Denys Vlasenkod5275882012-10-01 13:41:17 +020012724
12725 /* No arguments. Show the list of exported or readonly vars.
12726 * -n is ignored.
12727 */
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012728 showvars(argv[0], flag, 0);
Eric Andersencb57d552001-06-28 07:25:16 +000012729 return 0;
12730}
12731
Eric Andersencb57d552001-06-28 07:25:16 +000012732/*
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012733 * Delete a function if it exists.
Eric Andersencb57d552001-06-28 07:25:16 +000012734 */
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000012735static void
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012736unsetfunc(const char *name)
Aaron Lehmannb6ecbdc2001-12-06 03:37:38 +000012737{
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012738 struct tblentry *cmdp;
Eric Andersencb57d552001-06-28 07:25:16 +000012739
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012740 cmdp = cmdlookup(name, 0);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012741 if (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION)
Denis Vlasenko5651bfc2007-02-23 21:08:58 +000012742 delete_cmd_entry();
Eric Andersenc470f442003-07-28 09:56:35 +000012743}
12744
Eric Andersencb57d552001-06-28 07:25:16 +000012745/*
Eric Andersencb57d552001-06-28 07:25:16 +000012746 * The unset builtin command. We unset the function before we unset the
12747 * variable to allow a function to be unset when there is a readonly variable
12748 * with the same name.
12749 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012750static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012751unsetcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersencb57d552001-06-28 07:25:16 +000012752{
12753 char **ap;
12754 int i;
Eric Andersenc470f442003-07-28 09:56:35 +000012755 int flag = 0;
Eric Andersencb57d552001-06-28 07:25:16 +000012756 int ret = 0;
12757
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012758 while ((i = nextopt("vf")) != 0) {
Eric Andersenc470f442003-07-28 09:56:35 +000012759 flag = i;
Eric Andersencb57d552001-06-28 07:25:16 +000012760 }
Eric Andersencb57d552001-06-28 07:25:16 +000012761
Denis Vlasenko2da584f2007-02-19 22:44:05 +000012762 for (ap = argptr; *ap; ap++) {
Eric Andersenc470f442003-07-28 09:56:35 +000012763 if (flag != 'f') {
12764 i = unsetvar(*ap);
12765 ret |= i;
12766 if (!(i & 2))
12767 continue;
12768 }
12769 if (flag != 'v')
Eric Andersencb57d552001-06-28 07:25:16 +000012770 unsetfunc(*ap);
Eric Andersencb57d552001-06-28 07:25:16 +000012771 }
Eric Andersenc470f442003-07-28 09:56:35 +000012772 return ret & 1;
Eric Andersencb57d552001-06-28 07:25:16 +000012773}
12774
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012775static const unsigned char timescmd_str[] ALIGN1 = {
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012776 ' ', offsetof(struct tms, tms_utime),
12777 '\n', offsetof(struct tms, tms_stime),
12778 ' ', offsetof(struct tms, tms_cutime),
12779 '\n', offsetof(struct tms, tms_cstime),
12780 0
12781};
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012782static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012783timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012784{
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012785 unsigned long clk_tck, s, t;
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012786 const unsigned char *p;
12787 struct tms buf;
12788
Bartosz Golaszewski5d2e4092014-06-22 14:01:13 +020012789 clk_tck = bb_clk_tck();
Eric Andersencb57d552001-06-28 07:25:16 +000012790 times(&buf);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012791
12792 p = timescmd_str;
12793 do {
12794 t = *(clock_t *)(((char *) &buf) + p[1]);
12795 s = t / clk_tck;
Denys Vlasenko8cd9f342010-06-18 15:36:48 +020012796 t = t % clk_tck;
12797 out1fmt("%lum%lu.%03lus%c",
12798 s / 60, s % 60,
12799 (t * 1000) / clk_tck,
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012800 p[0]);
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012801 p += 2;
12802 } while (*p);
Manuel Novoa III 4456f252003-08-13 17:48:47 +000012803
Eric Andersencb57d552001-06-28 07:25:16 +000012804 return 0;
12805}
12806
Mike Frysinger98c52642009-04-02 10:02:37 +000012807#if ENABLE_SH_MATH_SUPPORT
Eric Andersenc470f442003-07-28 09:56:35 +000012808/*
Denys Vlasenko1ed2fb42010-06-18 14:09:48 +020012809 * The let builtin. Partially stolen from GNU Bash, the Bourne Again SHell.
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012810 * Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
Eric Andersen90898442003-08-06 11:20:52 +000012811 *
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012812 * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
Eric Andersenc470f442003-07-28 09:56:35 +000012813 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012814static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012815letcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012816{
Denis Vlasenko68404f12008-03-17 09:00:54 +000012817 arith_t i;
Eric Andersenc470f442003-07-28 09:56:35 +000012818
Denis Vlasenko68404f12008-03-17 09:00:54 +000012819 argv++;
12820 if (!*argv)
Denis Vlasenkob012b102007-02-19 22:43:01 +000012821 ash_msg_and_raise_error("expression expected");
Denis Vlasenko68404f12008-03-17 09:00:54 +000012822 do {
Denis Vlasenkob29eb6e2009-04-02 13:46:27 +000012823 i = ash_arith(*argv);
Denis Vlasenko68404f12008-03-17 09:00:54 +000012824 } while (*++argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012825
Denis Vlasenkod9e15f22006-11-27 16:49:55 +000012826 return !i;
Eric Andersenc470f442003-07-28 09:56:35 +000012827}
Eric Andersenc470f442003-07-28 09:56:35 +000012828#endif
Eric Andersen74bcd162001-07-30 21:41:37 +000012829
Eric Andersenc470f442003-07-28 09:56:35 +000012830/*
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012831 * The read builtin. Options:
12832 * -r Do not interpret '\' specially
12833 * -s Turn off echo (tty only)
12834 * -n NCHARS Read NCHARS max
12835 * -p PROMPT Display PROMPT on stderr (if input is from tty)
12836 * -t SECONDS Timeout after SECONDS (tty or pipe only)
12837 * -u FD Read from given FD instead of fd 0
Eric Andersenc470f442003-07-28 09:56:35 +000012838 * This uses unbuffered input, which may be avoidable in some cases.
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012839 * TODO: bash also has:
12840 * -a ARRAY Read into array[0],[1],etc
12841 * -d DELIM End on DELIM char, not newline
12842 * -e Use line editing (tty only)
Eric Andersenc470f442003-07-28 09:56:35 +000012843 */
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012844static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012845readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
Eric Andersenc470f442003-07-28 09:56:35 +000012846{
Denys Vlasenko73067272010-01-12 22:11:24 +010012847 char *opt_n = NULL;
12848 char *opt_p = NULL;
12849 char *opt_t = NULL;
12850 char *opt_u = NULL;
12851 int read_flags = 0;
12852 const char *r;
Eric Andersenc470f442003-07-28 09:56:35 +000012853 int i;
12854
Denys Vlasenko73067272010-01-12 22:11:24 +010012855 while ((i = nextopt("p:u:rt:n:s")) != '\0') {
Denis Vlasenkobf0a2012006-12-26 10:42:51 +000012856 switch (i) {
Paul Fox02eb9342005-09-07 16:56:02 +000012857 case 'p':
Denys Vlasenko73067272010-01-12 22:11:24 +010012858 opt_p = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012859 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012860 case 'n':
Denys Vlasenko73067272010-01-12 22:11:24 +010012861 opt_n = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012862 break;
12863 case 's':
Denys Vlasenko73067272010-01-12 22:11:24 +010012864 read_flags |= BUILTIN_READ_SILENT;
Paul Fox02eb9342005-09-07 16:56:02 +000012865 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012866 case 't':
Denys Vlasenko73067272010-01-12 22:11:24 +010012867 opt_t = optionarg;
Paul Fox02eb9342005-09-07 16:56:02 +000012868 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012869 case 'r':
Denys Vlasenko73067272010-01-12 22:11:24 +010012870 read_flags |= BUILTIN_READ_RAW;
Paul Fox02eb9342005-09-07 16:56:02 +000012871 break;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012872 case 'u':
Denys Vlasenko73067272010-01-12 22:11:24 +010012873 opt_u = optionarg;
Denis Vlasenko59f351c2008-03-25 00:07:12 +000012874 break;
Paul Fox02eb9342005-09-07 16:56:02 +000012875 default:
12876 break;
12877 }
Eric Andersenc470f442003-07-28 09:56:35 +000012878 }
Paul Fox02eb9342005-09-07 16:56:02 +000012879
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012880 /* "read -s" needs to save/restore termios, can't allow ^C
12881 * to jump out of it.
12882 */
12883 INT_OFF;
Denys Vlasenko03dad222010-01-12 23:29:57 +010012884 r = shell_builtin_read(setvar2,
Denys Vlasenko73067272010-01-12 22:11:24 +010012885 argptr,
12886 bltinlookup("IFS"), /* can be NULL */
12887 read_flags,
12888 opt_n,
12889 opt_p,
12890 opt_t,
12891 opt_u
12892 );
Denys Vlasenko9e71e3c2012-09-06 13:28:10 +020012893 INT_ON;
Denis Vlasenko46aeab92009-03-31 19:18:17 +000012894
Denys Vlasenko73067272010-01-12 22:11:24 +010012895 if ((uintptr_t)r > 1)
12896 ash_msg_and_raise_error(r);
Denis Vlasenko037576d2007-10-20 18:30:38 +000012897
Denys Vlasenko73067272010-01-12 22:11:24 +010012898 return (uintptr_t)r;
Eric Andersenc470f442003-07-28 09:56:35 +000012899}
12900
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012901static int FAST_FUNC
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000012902umaskcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012903{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +000012904 static const char permuser[3] ALIGN1 = "ugo";
12905 static const char permmode[3] ALIGN1 = "rwx";
12906 static const short permmask[] ALIGN2 = {
Eric Andersenc470f442003-07-28 09:56:35 +000012907 S_IRUSR, S_IWUSR, S_IXUSR,
12908 S_IRGRP, S_IWGRP, S_IXGRP,
12909 S_IROTH, S_IWOTH, S_IXOTH
12910 };
12911
Denis Vlasenkoeb858492009-04-18 02:06:54 +000012912 /* TODO: use bb_parse_mode() instead */
12913
Eric Andersenc470f442003-07-28 09:56:35 +000012914 char *ap;
12915 mode_t mask;
12916 int i;
12917 int symbolic_mode = 0;
12918
12919 while (nextopt("S") != '\0') {
12920 symbolic_mode = 1;
12921 }
12922
Denis Vlasenkob012b102007-02-19 22:43:01 +000012923 INT_OFF;
Eric Andersenc470f442003-07-28 09:56:35 +000012924 mask = umask(0);
12925 umask(mask);
Denis Vlasenkob012b102007-02-19 22:43:01 +000012926 INT_ON;
Eric Andersenc470f442003-07-28 09:56:35 +000012927
Denis Vlasenko5cedb752007-02-18 19:56:41 +000012928 ap = *argptr;
12929 if (ap == NULL) {
Eric Andersenc470f442003-07-28 09:56:35 +000012930 if (symbolic_mode) {
12931 char buf[18];
12932 char *p = buf;
12933
12934 for (i = 0; i < 3; i++) {
12935 int j;
12936
12937 *p++ = permuser[i];
12938 *p++ = '=';
12939 for (j = 0; j < 3; j++) {
12940 if ((mask & permmask[3 * i + j]) == 0) {
12941 *p++ = permmode[j];
12942 }
12943 }
12944 *p++ = ',';
12945 }
12946 *--p = 0;
12947 puts(buf);
12948 } else {
12949 out1fmt("%.4o\n", mask);
12950 }
12951 } else {
Denis Vlasenkoaa744452007-02-23 01:04:22 +000012952 if (isdigit((unsigned char) *ap)) {
Eric Andersenc470f442003-07-28 09:56:35 +000012953 mask = 0;
12954 do {
12955 if (*ap >= '8' || *ap < '0')
Denys Vlasenkoecc2a2e2009-08-29 22:53:41 +020012956 ash_msg_and_raise_error(msg_illnum, argv[1]);
Eric Andersenc470f442003-07-28 09:56:35 +000012957 mask = (mask << 3) + (*ap - '0');
12958 } while (*++ap != '\0');
12959 umask(mask);
12960 } else {
12961 mask = ~mask & 0777;
12962 if (!bb_parse_mode(ap, &mask)) {
Denis Vlasenko3af3e5b2007-03-05 00:24:52 +000012963 ash_msg_and_raise_error("illegal mode: %s", ap);
Eric Andersenc470f442003-07-28 09:56:35 +000012964 }
12965 umask(~mask & 0777);
12966 }
12967 }
12968 return 0;
12969}
12970
Denys Vlasenkod5f1b1b2009-06-05 12:06:05 +020012971static int FAST_FUNC
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012972ulimitcmd(int argc UNUSED_PARAM, char **argv)
Eric Andersenc470f442003-07-28 09:56:35 +000012973{
Denys Vlasenkof3c742f2010-03-06 20:12:00 +010012974 return shell_builtin_ulimit(argv);
Eric Andersenc470f442003-07-28 09:56:35 +000012975}
12976
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012977/* ============ main() and helpers */
12978
12979/*
12980 * Called to exit the shell.
Denis Vlasenkoa624c112007-02-19 22:45:43 +000012981 */
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012982static void
12983exitshell(void)
12984{
12985 struct jmploc loc;
12986 char *p;
12987 int status;
12988
Denys Vlasenkobede2152011-09-04 16:12:33 +020012989#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
12990 save_history(line_input_state);
12991#endif
12992
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012993 status = exitstatus;
12994 TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
12995 if (setjmp(loc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000012996 if (exception_type == EXEXIT)
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000012997/* dash bug: it just does _exit(exitstatus) here
12998 * but we have to do setjobctl(0) first!
12999 * (bug is still not fixed in dash-0.5.3 - if you run dash
13000 * under Midnight Commander, on exit from dash MC is backgrounded) */
13001 status = exitstatus;
13002 goto out;
13003 }
13004 exception_handler = &loc;
13005 p = trap[0];
13006 if (p) {
13007 trap[0] = NULL;
13008 evalstring(p, 0);
Denys Vlasenko0800e3a2009-09-24 03:09:26 +020013009 free(p);
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013010 }
13011 flush_stdout_stderr();
13012 out:
13013 setjobctl(0);
13014 _exit(status);
13015 /* NOTREACHED */
13016}
13017
Denis Vlasenko5c67e3e2007-02-23 01:05:03 +000013018static void
13019init(void)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013020{
13021 /* from input.c: */
Denys Vlasenko82dd14a2010-05-17 10:10:01 +020013022 /* we will never free this */
13023 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013024
13025 /* from trap.c: */
13026 signal(SIGCHLD, SIG_DFL);
Denys Vlasenko7a7b0342009-12-04 04:18:31 +010013027 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13028 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13029 */
Denys Vlasenkocacb2cd2010-10-05 00:13:02 +020013030 signal(SIGHUP, SIG_DFL);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013031
13032 /* from var.c: */
13033 {
13034 char **envp;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013035 const char *p;
13036 struct stat st1, st2;
13037
13038 initvar();
13039 for (envp = environ; envp && *envp; envp++) {
13040 if (strchr(*envp, '=')) {
13041 setvareq(*envp, VEXPORT|VTEXTFIXED);
13042 }
13043 }
13044
Bernhard Reutner-Fischer200c1c42013-11-08 14:12:13 +010013045 setvar2("PPID", utoa(getppid()));
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013046#if ENABLE_ASH_BASH_COMPAT
13047 p = lookupvar("SHLVL");
Denys Vlasenko5680e982014-01-07 16:12:48 +010013048 setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT);
Denys Vlasenko3fa97af2014-04-15 11:43:29 +020013049 if (!lookupvar("HOSTNAME")) {
13050 struct utsname uts;
13051 uname(&uts);
13052 setvar2("HOSTNAME", uts.nodename);
13053 }
Bernhard Reutner-Fischer80f8cdf2013-11-08 14:25:24 +010013054#endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013055 p = lookupvar("PWD");
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013056 if (p) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013057 if (*p != '/' || stat(p, &st1) || stat(".", &st2)
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013058 || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino
13059 ) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013060 p = '\0';
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013061 }
13062 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013063 setpwd(p, 0);
13064 }
13065}
13066
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013067
13068//usage:#define ash_trivial_usage
Denys Vlasenko6b6af532011-03-08 10:24:17 +010013069//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]"
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013070//usage:#define ash_full_usage "\n\n"
13071//usage: "Unix shell interpreter"
13072
13073//usage:#if ENABLE_FEATURE_SH_IS_ASH
13074//usage:# define sh_trivial_usage ash_trivial_usage
13075//usage:# define sh_full_usage ash_full_usage
13076//usage:#endif
13077//usage:#if ENABLE_FEATURE_BASH_IS_ASH
13078//usage:# define bash_trivial_usage ash_trivial_usage
13079//usage:# define bash_full_usage ash_full_usage
13080//usage:#endif
13081
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013082/*
13083 * Process the shell command line arguments.
13084 */
13085static void
Denis Vlasenko68404f12008-03-17 09:00:54 +000013086procargs(char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013087{
13088 int i;
13089 const char *xminusc;
13090 char **xargv;
13091
13092 xargv = argv;
13093 arg0 = xargv[0];
Denis Vlasenko68404f12008-03-17 09:00:54 +000013094 /* if (xargv[0]) - mmm, this is always true! */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013095 xargv++;
13096 for (i = 0; i < NOPTS; i++)
13097 optlist[i] = 2;
13098 argptr = xargv;
Denys Vlasenkob0b83432011-03-07 12:34:59 +010013099 if (options(/*cmdline:*/ 1)) {
Denis Vlasenko28bf6712008-02-14 15:01:47 +000013100 /* it already printed err message */
13101 raise_exception(EXERROR);
13102 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013103 xargv = argptr;
13104 xminusc = minusc;
13105 if (*xargv == NULL) {
13106 if (xminusc)
13107 ash_msg_and_raise_error(bb_msg_requires_arg, "-c");
13108 sflag = 1;
13109 }
13110 if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1))
13111 iflag = 1;
13112 if (mflag == 2)
13113 mflag = iflag;
13114 for (i = 0; i < NOPTS; i++)
13115 if (optlist[i] == 2)
13116 optlist[i] = 0;
13117#if DEBUG == 2
13118 debug = 1;
13119#endif
13120 /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
13121 if (xminusc) {
13122 minusc = *xargv++;
13123 if (*xargv)
13124 goto setarg0;
13125 } else if (!sflag) {
13126 setinputfile(*xargv, 0);
13127 setarg0:
13128 arg0 = *xargv++;
13129 commandname = arg0;
13130 }
13131
13132 shellparam.p = xargv;
13133#if ENABLE_ASH_GETOPTS
13134 shellparam.optind = 1;
13135 shellparam.optoff = -1;
13136#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013137 /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013138 while (*xargv) {
13139 shellparam.nparam++;
13140 xargv++;
13141 }
13142 optschanged();
13143}
13144
13145/*
13146 * Read /etc/profile or .profile.
13147 */
13148static void
13149read_profile(const char *name)
13150{
13151 int skip;
13152
13153 if (setinputfile(name, INPUT_PUSH_FILE | INPUT_NOFILE_OK) < 0)
13154 return;
13155 skip = cmdloop(0);
13156 popfile();
13157 if (skip)
13158 exitshell();
13159}
13160
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013161/*
13162 * This routine is called when an error or an interrupt occurs in an
13163 * interactive shell and control is returned to the main command loop.
13164 */
13165static void
13166reset(void)
13167{
13168 /* from eval.c: */
13169 evalskip = 0;
13170 loopnest = 0;
13171 /* from input.c: */
Denis Vlasenko41eb3002008-11-28 03:42:31 +000013172 g_parsefile->left_in_buffer = 0;
13173 g_parsefile->left_in_line = 0; /* clear input buffer */
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013174 popallfiles();
13175 /* from parser.c: */
13176 tokpushback = 0;
13177 checkkwd = 0;
13178 /* from redir.c: */
Denis Vlasenko34c73c42008-08-16 11:48:02 +000013179 clearredir(/*drop:*/ 0);
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013180}
13181
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013182#if PROFILE
13183static short profile_buf[16384];
13184extern int etext();
13185#endif
13186
Denis Vlasenkobc54cff2007-02-23 01:05:52 +000013187/*
13188 * Main routine. We initialize things, parse the arguments, execute
13189 * profiles if we're a login shell, and then call cmdloop to execute
13190 * commands. The setjmp call sets up the location to jump to when an
13191 * exception occurs. When an exception occurs the variable "state"
13192 * is used to figure out how far we had gotten.
13193 */
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +000013194int ash_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +000013195int ash_main(int argc UNUSED_PARAM, char **argv)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013196{
Mike Frysinger98c52642009-04-02 10:02:37 +000013197 const char *shinit;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013198 volatile smallint state;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013199 struct jmploc jmploc;
13200 struct stackmark smark;
13201
Denis Vlasenko01631112007-12-16 17:20:38 +000013202 /* Initialize global data */
13203 INIT_G_misc();
13204 INIT_G_memstack();
13205 INIT_G_var();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013206#if ENABLE_ASH_ALIAS
Denis Vlasenko01631112007-12-16 17:20:38 +000013207 INIT_G_alias();
Denis Vlasenkoee87ebf2007-12-21 22:18:16 +000013208#endif
Denis Vlasenko01631112007-12-16 17:20:38 +000013209 INIT_G_cmdtable();
13210
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013211#if PROFILE
13212 monitor(4, etext, profile_buf, sizeof(profile_buf), 50);
13213#endif
13214
13215#if ENABLE_FEATURE_EDITING
13216 line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP);
13217#endif
13218 state = 0;
13219 if (setjmp(jmploc.loc)) {
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013220 smallint e;
Denis Vlasenko4e12b1a2008-12-23 23:36:47 +000013221 smallint s;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013222
13223 reset();
13224
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013225 e = exception_type;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013226 if (e == EXERROR)
13227 exitstatus = 2;
13228 s = state;
Denys Vlasenkob563f622010-09-25 17:15:13 +020013229 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013230 exitshell();
Denys Vlasenkob563f622010-09-25 17:15:13 +020013231 }
13232 if (e == EXINT) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013233 outcslow('\n', stderr);
Denys Vlasenkob563f622010-09-25 17:15:13 +020013234 }
Denis Vlasenko7f88e342009-03-19 03:36:18 +000013235
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013236 popstackmark(&smark);
13237 FORCE_INT_ON; /* enable interrupts */
13238 if (s == 1)
13239 goto state1;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013240 if (s == 2)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013241 goto state2;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013242 if (s == 3)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013243 goto state3;
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013244 goto state4;
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013245 }
13246 exception_handler = &jmploc;
13247#if DEBUG
13248 opentrace();
Denis Vlasenko653d8e72009-03-19 21:59:35 +000013249 TRACE(("Shell args: "));
Denis Vlasenkofe1f00a2007-02-23 01:04:50 +000013250 trace_puts_args(argv);
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013251#endif
13252 rootpid = getpid();
13253
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013254 init();
13255 setstackmark(&smark);
Denis Vlasenko68404f12008-03-17 09:00:54 +000013256 procargs(argv);
13257
Denys Vlasenko6088e132010-12-25 23:58:42 +010013258 if (argv[0] && argv[0][0] == '-')
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013259 isloginsh = 1;
13260 if (isloginsh) {
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013261 const char *hp;
13262
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013263 state = 1;
13264 read_profile("/etc/profile");
13265 state1:
13266 state = 2;
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013267 hp = lookupvar("HOME");
13268 if (hp) {
13269 hp = concat_path_file(hp, ".profile");
13270 read_profile(hp);
13271 free((char*)hp);
13272 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013273 }
13274 state2:
13275 state = 3;
13276 if (
13277#ifndef linux
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013278 getuid() == geteuid() && getgid() == getegid() &&
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013279#endif
Denis Vlasenko0c032a42007-02-23 01:03:40 +000013280 iflag
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013281 ) {
13282 shinit = lookupvar("ENV");
13283 if (shinit != NULL && *shinit != '\0') {
13284 read_profile(shinit);
13285 }
13286 }
13287 state3:
13288 state = 4;
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013289 if (minusc) {
13290 /* evalstring pushes parsefile stack.
13291 * Ensure we don't falsely claim that 0 (stdin)
Denis Vlasenko5368ad52009-03-20 10:20:08 +000013292 * is one of stacked source fds.
13293 * Testcase: ash -c 'exec 1>&0' must not complain. */
Denys Vlasenko79b3d422010-06-03 04:29:08 +020013294 // if (!sflag) g_parsefile->pf_fd = -1;
Denys Vlasenko08d8b3c2010-06-03 04:28:28 +020013295 // ^^ not necessary since now we special-case fd 0
13296 // in is_hidden_fd() to not be considered "hidden fd"
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013297 evalstring(minusc, 0);
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013298 }
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013299
13300 if (sflag || minusc == NULL) {
Denys Vlasenko4840ae82011-09-04 15:28:03 +020013301#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY
Denis Vlasenko2f5d0cd2008-06-23 13:24:19 +000013302 if (iflag) {
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013303 const char *hp = lookupvar("HISTFILE");
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013304 if (!hp) {
13305 hp = lookupvar("HOME");
Stefan Hellermann4ef14392013-03-15 02:45:50 +010013306 if (hp) {
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013307 hp = concat_path_file(hp, ".ash_history");
Bernhard Reutner-Fischer200c1c42013-11-08 14:12:13 +010013308 setvar2("HISTFILE", hp);
Stefan Hellermannaeb717a2013-03-03 15:29:32 +010013309 free((char*)hp);
13310 hp = lookupvar("HISTFILE");
13311 }
13312 }
Denis Vlasenko5c2b8142009-03-19 01:59:59 +000013313 if (hp)
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013314 line_input_state->hist_file = hp;
Denys Vlasenko2c4de5b2011-03-31 13:16:52 +020013315# if ENABLE_FEATURE_SH_HISTFILESIZE
13316 hp = lookupvar("HISTFILESIZE");
13317 line_input_state->max_history = size_from_HISTFILESIZE(hp);
13318# endif
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013319 }
13320#endif
13321 state4: /* XXX ??? - why isn't this before the "if" statement */
13322 cmdloop(1);
13323 }
13324#if PROFILE
13325 monitor(0);
13326#endif
13327#ifdef GPROF
13328 {
13329 extern void _mcleanup(void);
13330 _mcleanup();
13331 }
13332#endif
Denys Vlasenkob563f622010-09-25 17:15:13 +020013333 TRACE(("End of main reached\n"));
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013334 exitshell();
13335 /* NOTREACHED */
13336}
13337
Denis Vlasenkoa624c112007-02-19 22:45:43 +000013338
Eric Andersendf82f612001-06-28 07:46:40 +000013339/*-
13340 * Copyright (c) 1989, 1991, 1993, 1994
Eric Andersen2870d962001-07-02 17:27:21 +000013341 * The Regents of the University of California. All rights reserved.
Eric Andersendf82f612001-06-28 07:46:40 +000013342 *
13343 * This code is derived from software contributed to Berkeley by
13344 * Kenneth Almquist.
13345 *
13346 * Redistribution and use in source and binary forms, with or without
13347 * modification, are permitted provided that the following conditions
13348 * are met:
13349 * 1. Redistributions of source code must retain the above copyright
13350 * notice, this list of conditions and the following disclaimer.
13351 * 2. Redistributions in binary form must reproduce the above copyright
13352 * notice, this list of conditions and the following disclaimer in the
13353 * documentation and/or other materials provided with the distribution.
"Vladimir N. Oleynik"ddc280e2005-12-15 12:01:49 +000013354 * 3. Neither the name of the University nor the names of its contributors
Eric Andersendf82f612001-06-28 07:46:40 +000013355 * may be used to endorse or promote products derived from this software
13356 * without specific prior written permission.
13357 *
13358 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
13359 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13360 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13361 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13362 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13363 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
13364 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
13365 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
13366 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
13367 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
13368 * SUCH DAMAGE.
13369 */